电子产业一站式赋能平台

PCB联盟网

搜索
查看: 262|回复: 0
收起左侧

嵌入式软件出现内存泄漏的时候,如何进行排查和分析?

[复制链接]

568

主题

568

帖子

4221

积分

四级会员

Rank: 4

积分
4221
发表于 2025-1-10 17:50:00 | 显示全部楼层 |阅读模式
我是老温,一名热爱学习的嵌入式工程师
" n- g6 r  X: ~! o关注我,一起变得更加优秀!1.内存泄漏问题原理1.1堆内存在C代码中的存储方式内存泄漏问题只有在使用堆内存的时候才会出现,栈内存不存在内存泄漏问题,因为栈内存会自动分配和释放。C代码中堆内存的申请函数是malloc,常见的内存申请代码如下:" Q- T9 w0 H0 E! N* a
char *info = NULL;    /**转换后的字符串**/
& D- X7 Z( Q0 l, vinfo = (char*)malloc(NB_MEM_SPD_INFO_MAX_SIZE);( S! l/ A. j0 J& Q4 M2 q2 x
if( NULL == info)/ N5 G# C1 U8 G, w2 S
{
$ h3 l) U( \* R; ]" S$ }    (void)tdm_error("malloc error!
4 U7 a, R: p' u) ]) m3 @7 H$ K, X");1 {( v  |* m% ~9 z
    return NB_SA_ERR_HPI_OUT_OF_MEMORY;- S; j% R" s- @) L# n
}7 N4 m2 i9 z* ?: N7 O7 @
由于malloc函数返回的实际上是一个内存地址,所以保存堆内存的变量一定是一个指针(除非代码编写极其不规范)。
- Y9 h7 w' A; a5 B8 U再重复一遍,保存堆内存的变量一定是一个指针,这对本文主旨的理解很重要。当然,这个指针可以是单指针,也可以是多重指针。
! r1 v" J. ?: G& Q! m2 J; J) xmalloc函数有很多变种或封装,如g_malloc、g_malloc0、VOS_Malloc等,这些函数最终都会调用malloc函数。
+ w0 @9 d2 X! d1 I3 K9 E' r1.2堆内存的获取方法看到本小节标题,可能有些同学有疑惑,上一小节中的malloc函数,不就是堆内存的获取方法吗?7 }- d7 U/ q& i  h. M
的确是,通过malloc函数申请是最直接的获取方法,如果只知道这种堆内存获取方法,就容易掉到坑里了。一般的来讲,堆内存有如下两种获取方法:
" \0 Y5 i( b' U/ y方法一:将函数返回值直接赋给指针,一般表现形式如下:& Z; r! l: S% S, |. S9 B
char *local_pointer_xx = NULL;- v& e! d" q+ p. N# c
local_pointer_xx = (char*)function_xx(para_xx, …);
& T8 A( }1 T6 }3 Y8 e该类涉及到内存申请的函数,返回值一般都指针类型,例如:: R" }8 ]3 q2 ]2 m- g
GSList* g_slist_append (GSList   *list, gpointer  data);3 [6 y* I0 e5 e! z5 l
方法二:将指针地址作为函数返回参数,通过返回参数保存堆内存地址,一般表现形式如下:
6 |  p) k! r/ Yint ret;
  v. T  N, b: A& p. h& A0 f/ bchar *local_pointer_xx = NULL;    /**转换后的字符串**/
7 L- \" Z! Y2 d8 _: wret = (char*)function_xx(..., &local_pointer_xx, ...);
0 {! @4 N/ l- [5 u8 ?* ~# `该类涉及到内存申请的函数,一般都有一个入参是双重指针,例如:+ e' F0 ?) |3 ^% N  Z2 ?& `: c4 ~6 h+ t
__STDIO_INLINE _IO_ssize_t;6 ?, [: P6 b9 V# b
getline (char **__lineptr, size_t *__n, FILE *__stream);9 `) L7 q& C- H7 F# D
前面说通过malloc申请内存,就属于方法一的一个具体表现形式。其实这两类方法的本质是一样的,都是函数内部间接申请了内存,只是传递内存的方法不一样,方法一通过返回值传递内存指针,方法二通过参数传递内存指针。
; h* {0 c. @% ?9 `, j+ P1.3内存泄漏三要素最常见的内存泄漏问题,包含以下三个要素:% w4 Y1 Q! d; [7 `+ [
要素一:函数内有局部指针变量定义;
8 \. i. Q6 ~: F( r& H要素二:对该局部指针有通过上一小节中“两种堆内存获取方法”之一获取内存;
8 @5 y7 h  q- ]9 t要素三:在函数返回前(含正常分支和异常分支)未释放该内存,也未保存到其它全局变量或返回给上一级函数。8 C  z2 e2 T4 s9 e
1.4内存释放误区稍微使用过C语言编写代码的人,都应该知道堆内存申请之后是需要释放的。但为何还这么容易出现内存泄漏问题呢?8 ~  I: M' c" G8 B; ]" Q! Q
一方面,是开发人员经验不足、意识不到位或一时疏忽导致;另一方面,是内存释放误区导致。很多开发人员,认为要释放的内存应该局限于以下两种:* J0 u1 l0 U$ P9 K* c
1) 直接使用内存申请函数申请出来的内存,如malloc、g_malloc等;
' r8 y8 g5 R' h- Y2)该开发人员熟悉的接口中,存在内存申请的情况,如iBMC的兄弟,都应该知道调用如下接口需要释放list指向的内存:
! D% ]7 d/ @$ X2 u5 Gdfl_get_object_list(const char* class_name, GSList **list);. @7 u  A% s3 o6 R
按照以上思维编写代码,一旦遇到不熟悉的接口中需要释放内存的问题,就完全没有释放内存的意识,内存泄漏问题就自然产生了。
0 ^& X8 ~7 j% }* I; |2.内存泄漏问题检视方法检视内存泄漏问题,关键还是要养成良好的编码检视习惯。与内存泄漏三要素对应,需' {9 _3 h1 R: ^! m
要做到如下三点:% Z$ r' K) X0 ~& d$ I# o, M
1) 在函数中看到有局部指针,就要警惕内存泄漏问题,养成进一步排查的习惯
1 J* b. E: b6 R, _& T' M" H2) 分析对局部指针的赋值操作,是否属于前面所说的“两种堆内存获取方法”之一,如果是,就要分析函数返回的指针到底指向啥?
; l' D+ k) t: c1 o- {是全局数据、静态数据还是堆内存?对于不熟悉的接口,要找到对应的接口文档或源代码分析;又或者看看代码中其它地方对该接口的引用,是否进行了内存释放;
% R3 `% X4 |1 \( @3) 如果确认对局部指针存在内存申请操作,就需要分析该内存的去向,是会被保存在全局变量吗?又或者会被作为函数返回值吗?如果都不是,就需要排查函数所有有”return“的地方,保证内存被正确释放。& J& T' ]; p2 f: K% F& m
原文:https://my.oschina.net/u/4526289/blog/4539592
1 E# R' q0 X; @; S
5 C3 [3 U1 i% j) H2 V: v-END-
& `/ B* i7 e0 N* d6 c# l往期推荐:点击图片即可跳转阅读
$ B% l$ o$ C$ G! Q% M+ |) X7 \4 ]) e  X8 h0 Z( ?' L
                                                        - T- t5 q+ d" [% X
                                                                ( Y; K' [3 a6 P: K
                                                                        " ^9 `. W% S) K1 w
                                                                                9 c2 i0 g5 V7 [( u5 R7 ?; v

irze1x03bu164051385505.jpg

irze1x03bu164051385505.jpg

, n  ?. Q% N" m( C- N                                                                               
! f! r9 l$ O9 f; Y0 E( I                                                                                        2025年,抽屉里的嵌入式开发板,早就已经写满了岁月的痕迹!
/ ?! r# O9 w& I% }8 ^) ~" K9 \                                                                               
1 Q2 o% t8 `3 N. C6 C9 D2 Z                                                                       
; x) A2 I( x6 N- }                                                               
8 H8 X# c4 `3 U) s$ x6 S, @                                                       
. k0 ~. W" i- _! M8 A                                               
3 a8 q) L8 I# \! @
! y8 |2 o# I8 g, [/ F                                                       
' b0 N" T( x" m                                                               
3 ^+ U* t. V$ f0 h' I                                                                        , S, N8 C2 b, p. ~5 P9 r5 k1 ^
                                                                               
2 r1 \6 I3 T6 C9 |8 f5 {

kkdmnu4ouj564051385605.jpg

kkdmnu4ouj564051385605.jpg
/ E0 E8 s( J8 ?) n
                                                                               
9 j6 p  J, K' w) s/ S8 ]: S2 ^) \                                                                                        一些不太成熟的嵌入式系统设计观念!
- b" C- x+ D3 j7 g. {. O                                                                               
- z" n% j( z8 E- S1 `                                                                       
8 X9 E1 b. K; M2 m2 Y7 I                                                                ) N, s7 `+ {4 B6 t4 x" m$ h
                                                        # O; Y6 f6 u) n$ a  e. C& z
                                               
4 d% s; T; ~  L/ L' Y5 x6 v5 ~7 @3 Q4 [  e% D
                                                        ' v6 E" ~2 B0 w
                                                               
+ P1 M7 [7 x1 B4 ]2 k# l                                                                        7 j! r( h/ ^% I% m: R9 [, K* B
                                                                               
) y  U; Y0 v0 {4 M; Y

345wlygzsfk64051385705.jpg

345wlygzsfk64051385705.jpg

& Y( |+ Z% J  e+ j) O# g/ Z                                                                               
4 l0 E* E1 ^& X3 G% {                                                                                        嵌入式软件OTA升级,有哪几种FLASH划分方式?
5 \( q4 @' j* |2 U% t                                                                               
; U& n0 b7 ~* B                                                                       
7 u0 G+ Q- \3 G2 A* y' {( v                                                                4 I- F) ~& l$ S3 |, r9 R3 T
                                                       
9 n  o4 C5 |. ^                                                ( X% U& V! _& D
我是老温,一名热爱学习的嵌入式工程师2 q2 s! h; D: X/ B) f- p0 y/ k
关注我,一起变得更加优秀!7 r+ |( p5 V) U' _9 Q

0zgnxu5mfff64051385806.png

0zgnxu5mfff64051385806.png
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表