|
我是老温,一名热爱学习的嵌入式工程师4 B4 U! b; O( P$ I% `! P C: N
关注我,一起变得更加优秀!一. 常见错误与预防 1. 分配后忘记释放内存void func(void)
/ [1 G9 Z: F$ |& u" H4 |. A. I{
) G3 I3 M0 [4 W( n p = malloc(len);% i# a0 {! |/ f; R/ w: Q' S% f6 y
do_something(p);
- g( O) u6 d& `6 Q2 [- z4 S: Z' L return; /*错误!退出程序时没有释放内存*/
! {( Z) \( O- ~! o( C}
. d9 o5 v1 p. D/ ]预防: 编写代码时malloc()和free()保证成对出现,避免忘记资源回收。
# @* A& o" t8 j5 E; P! Wint func(void)
- V: e' M7 g: {3 c* W7 Z; u{
8 h$ x) i1 b" Q6 u- f p = malloc(len);
+ ]* ]: y1 a* \* O if (condition)
( [* N$ Z0 ]# I( U7 y return -1; /*错误!退出程序时没有释放内存*/: J/ n% }8 N: p
free(p);
; S( Y: \' ~/ B* S/ k2 V" H return 0;
7 q* d3 D \7 x' S% ^( P, ~}
" q# N9 A4 \" e预防: 一旦使用动态内存分配,请仔细检查程序的退出分支是否已经释放该动态内存。& H7 V: N( t$ G7 x# T7 Q t' Z
2. 释放内存调用错误指针void func(void)0 I F* m& r" z/ S2 ~, l/ f
{# H* h2 i2 O! P+ Q7 O' f2 X# F
p = malloc(len);
! ~2 u8 t! e+ m; B val = *p++; /*错误!动态内存句柄不可移动*/& K, D( Y: a. C- g; c3 x
free(p);) P) x* ?6 K3 B5 J+ O# R$ ^
}
3 E3 X- |$ n8 y( @) N! {预防: 千万不要修改动态内存句柄!可以另外赋值给其他指针变量,再对该动态内存进行访问操作。 g. L }" Z; y7 k
3. 分配内存不够导致溢出void func(void)
2 k. L/ x2 s. u5 r3 l& r{ E8 l; k' [, q% Q1 i) @2 j
len = strlen(str);
# V- z/ u$ ~7 W$ ^/ |7 H p = malloc(len);
3 E |5 V! V4 n strcpy(p, str); /*错误!str的’\0’写到动态内存外*/
% U' ~: A0 s3 g* U}
! u" b7 M+ j8 I4 J预防: 分配内存前仔细思考长度是否足够,千万注意字符串拷贝占用内存比字符串长度大1。 o- \ d/ Q) ]
二. 自动查错机制 尽管在开发过程中坚守原则和谨慎编程甚至严格测试,然而内存泄露的错误还是难以杜绝,如何让系统自动查出内存泄露的错误呢?
, _+ Q5 M# }3 D一种比较好的方法是建立日志块,即每次分配内存时记录该内存块的指针和大小,释放时再去除该日志块,如果有内存泄露就会有对应的日志块记录这些内存没有释放,这样就可以提醒程序员进行查错。, g. m2 n2 W1 D( W9 {: P
有了上述日志块操作函数,再来实现动态内存分配与释放函数就很容易了。只有当处于DEBUG版本和打开内存调试DMEM_DBG时才进行日志登录,否则MallocExt()和FreeExt()函数与malloc()和free()是等价的,这样保证了系统处于发布版本时的性能。( c& y2 O1 p1 G$ u: D3 G4 e
(代码已经过严格测试,但这不是盈利的商业代码,即没有版权。但如果因代码错误带来的任何损失作者具有免责权利)2 l# c) i4 C6 e# @& Y5 U
代码部分:首先定义日志块结构体:
]( R% i" g& L+ F. u/* Log of dynamic memory usage */* C. o. A9 `( _6 n& _
typedef struct _dmem_log; c4 N( P0 M+ M* u
{
" ^; S* t5 a3 Z9 {7 b q struct _dmem_log *p_stNext; /* Point to next log */
4 |1 T+ t+ @: } const void *p_vDMem; /* Point to allocated memory by this pointer */2 x- A+ X& |7 ]7 j. h9 F! s
INT32S iSize; /* Size of the allocated memory */- b( V, w3 `0 c Y7 r) F
} DMEM_LOG;
3 r$ m$ g8 x7 W h7 M& {# D! l" O然后为该结构体开辟内存:
& D' B6 s( Q# R* J) B) r- N gstatic DMEM_LOG *s_pstFreeLog; /* Point to free log pool by this pointer */
/ E6 |+ U* s3 f- {$ Astatic INT8U s_byNumUsedLog;' @6 M8 k S& c& g/ r" d
static DMEM_LOG *s_pstHeadLog; /* Point to used log chain by this pointer */8 k2 f' f9 ^" I ]
/* Pool of dynamic memory log */* d5 F4 I' D' S# X
#define NUM_DMEM_LOG 20
' I+ K/ M: X; a* Sstatic DMEM_LOG s_astDMemLog[NUM_DMEM_LOG];# _# w3 i4 j/ v" E( D5 K
下面是内存日志块的操作函数:初始化、插入日志和移除日志:; k% h: J- }, y1 d6 h- `& x9 I
/********************************************************** * Initialize DMem Log
' d; E! H2 e5 J; X/ { ~7 ^% f* Description : Initialize log of dynamic memory2 z& T5 [. a1 M9 Z/ D% P' M7 {/ C
* Arguments : void( W- T, J+ [6 U: H
* Returns : void. j# | E) z8 @9 e( D
* Notes :. v' h) m6 u: i( S! @0 }7 n/ _
**********************************************************/- N4 z& T4 y* I0 a2 S4 }% w9 n& w/ R. k
static void InitDMemLog(void)
9 l& k' ]( x1 E& w& J! j{. ]* o7 v: }4 R! L
INT16S nCnt;/ Y/ f+ D0 V& \, i7 h! m
/* Initialize pool of log */ [+ t" W2 e0 }" q
for (nCnt = 0; nCnt ' _1 {+ i5 W# i) X3 b
{6 h" A1 n1 R: k6 q5 d+ \- M
/* Point to next one */
' B3 G4 z( m3 x% v5 `& F; A s_astDMemLog[nCnt].p_stNext = &s_astDMemLog[nCnt + 1];
: E1 A+ u, {) m! ^ }7 ` U5 F* i* H4 w8 g8 e
s_astDMemLog[NUM_DMEM_LOG - 1].p_stNext = NULL;: s( w; H0 I F3 O& y- [" [8 c3 ]
s_pstFreeLog = &s_astDMemLog[0]; /* Point to the 1th log */9 c+ v( @; v9 L. o2 k' l. m, V4 j
return;
$ v: `8 B/ l" d( x" S, T8 t. j}
3 J0 p+ P" ?2 A! [& L/********************************************************** * Log DMem
& u1 O$ H/ g% i9 v) v5 z( ~* Description : Join an allocated memory into log pool) r5 R0 w* w1 a8 W9 ^4 f
* Arguments : const void *p_vAddr point to address of this allocated memory by this pointer
) W2 x% ]6 t7 N- S/ U3 @* h* INT32S iSize size of this allocated memory
6 Q c7 n/ U& s3 p9 ]5 U/ o. j1 W* Returns : void6 G v0 ?9 u5 G
* Notes :) d3 ~# y' W$ m& ~7 G( ~7 [; t
**********************************************************/6 c. {3 k3 { {6 t- {0 r/ j( J
static void LogDMem(const void *p_vAddr, INT32S iSize)
) Z, `9 x; r0 j0 O$ u% T{2 }& t- I' Z& v8 z8 z$ t6 U& D; V
ASSERT(p_vAddr && iSize > 0);
8 Z* u) b% N- _2 K0 X DMEM_LOG *p_stLog;
8 h5 Q6 J1 H& Y6 C #if OS_CRITICAL_METHOD == 3
( O2 M4 |* e; ]/ R OS_CPU_SR cpu_sr;; W, _( {0 _' u9 G
#endif7 v, ~( ^" g! d$ X( s
+ R( t7 r" x; U1 ]7 B
/* Get a log from free pool */$ x: s; U @/ V: y/ A' ?3 i
OS_ENTER_CRITICAL(); /* Avoid race condition on s_pstFreeLog */+ F( m2 [4 K% G# t0 Z- Z+ N6 ?) \+ U
if (!s_pstFreeLog)
6 v- e( F6 b! @; ? \* a7 } {
+ e! f3 C! E Z; u7 H OS_EXIT_CRITICAL();
8 {$ [( h, D0 p5 b7 K1 _8 v PRINTF("Allocate DMemLog failed.\r
; L. M8 G: N( a ~7 _7 {2 `; I");
" [2 q0 W {3 p( w3 ]- k+ S3 f' | return;! B1 g, c' X; |; o7 L' D/ L
}" I9 J8 J8 S+ V
p_stLog = s_pstFreeLog;
) B# a7 \* c! P# D; t s_pstFreeLog = s_pstFreeLog->p_stNext;
7 R% T- o5 X1 u5 Z% k' B OS_EXIT_CRITICAL();: l/ M$ o+ p/ |$ r! ]
0 c; I# ~. g/ V8 \6 V /* Don't need to protect this log that is free one currently */+ b$ i& l, ^/ a# m& w$ a0 S/ y" ^
p_stLog->p_vDMem = p_vAddr;
: Q! D. z1 I6 ~/ L0 a8 ?* L1 W p_stLog->iSize = iSize;
% k# W, Y3 i2 T% G5 ~: \ /* Put this log into used chain */
0 i- {9 c( t1 @0 b& _2 \ OS_ENTER_CRITICAL(); /* Avoid race condition */0 G1 Q: N; B+ j) E7 V' S. j
p_stLog->p_stNext = s_pstHeadLog;
1 i% \, P5 M) \" _& T s_pstHeadLog = p_stLog;
% ]" Z* i, z$ ?: G' n1 e ++s_byNumUsedLog;
0 c; X8 N: M5 w5 N# M% N5 d OS_EXIT_CRITICAL();, W* v4 F, v4 ~) p1 G8 x
; S* V" M; l4 ]" ]* Y/ |
return;9 c- U) H$ a6 { e/ M4 ?
}
* c$ Z; h/ J' F, _/********************************************************** * Unlog DMem
- g+ }+ N B7 ]3 Z* Description : Remove an allocated memory from log pool
0 H4 Z4 n$ x `* Arguments : const void *p_vAddr point to address of this allocated memory by this pointer; e8 C- @' [5 ~6 j
* Returns : void) K+ i% I8 Y" \4 F6 K+ O3 j- x: o
* Notes :
0 V& S* [4 X3 S**********************************************************/
2 m" I, G/ J( Y; j" M. f" x# kstatic void UnlogDMem(const void *p_vAddr)# D+ S& l& r* W7 ?$ W
{
# h$ N3 a% g! Z/ j# k8 u8 a, ^ ASSERT(p_vAddr);
m1 b& P" N- v5 ] DMEM_LOG *p_stLog, *p_stPrev;
5 ~0 w$ i- H! ?0 w8 R #if OS_CRITICAL_METHOD == 3
6 }- ~/ c6 G* X3 g8 h OS_CPU_SR cpu_sr;* T% H) ~( c3 O$ a
#endif& |2 `( ~( R- Q, e! P
/* Search the log */
0 c! N9 ^& r0 [ OS_ENTER_CRITICAL(); /*Avoid race condition */
7 B( o8 I* h) N# l# P p_stLog = p_stPrev = s_pstHeadLog;
& F d- Q0 y& v# R while (p_stLog)
6 l; x9 C* j/ O1 z9 q7 h6 ~ {" R% S' _; v& T, T7 }5 Q2 Q
if (p_vAddr == p_stLog->p_vDMem)
& r! o# O6 o# V) @- _# T {. l- J/ ^$ {$ |0 W% f6 J$ V
break; /* Have found */
5 Q+ [7 J* d! ?9 V0 {" {: A( [6 A* a }
% o7 ]+ K& L7 r' ~; r, J p_stPrev = p_stLog;
- {2 }! M$ k) Y; \; P7 ]* L p_stLog = p_stLog->p_stNext; /* Move to next one */
3 q& F0 Y/ h# K% a$ X" E: B: U }
0 {4 Q4 [% u; q 4 `: c% m/ d0 |$ [0 p5 F( |
if (!p_stLog)
' s) B9 U/ J% J% c3 v) u {% M: Y4 a& _# F; l$ a+ y9 m! U
OS_EXIT_CRITICAL();3 n! P5 F3 g! g- D( C, J( I2 i2 S. S
PRINTF("Search Log failed.\r
% S2 p$ o( W$ p! D- V");
) J( |7 I: c( U5 a7 H return;# L+ G# H. Q& ?0 x0 A( ^
}
* R' I* z6 V$ c1 o2 U" J% @1 Q /* Remove from used pool */1 p- R% j( ?0 X0 a1 T2 }' K Y
if (p_stLog == s_pstHeadLog)* H8 k! [3 Q$ Q8 F2 R9 A E
{
M+ a% ~6 T* u' @* V2 X s_pstHeadLog = s_pstHeadLog->p_stNext;- c" a; t3 |* [; @ o g4 y8 O1 V
}
. w3 Y2 j& n% q0 p. p7 R/ S! t else
, B8 m% _/ e$ N4 o {6 a, M! _: J6 f+ C4 e+ d
p_stPrev->p_stNext = p_stLog->p_stNext;
8 s( E* C' S6 U% h/ x+ H" [ K }/ `) R# e' \) y7 Q8 y. M. l- E
--s_byNumUsedLog;! \8 R0 y @5 x/ r
OS_EXIT_CRITICAL();. \& A& A# K5 G1 _ R+ t' y; Y
/* Don't need to protect this log that is free one currently */, O# d: Q* l$ W
p_stLog->p_vDMem = NULL;1 j0 s+ P4 @4 U, a+ k1 t
p_stLog->iSize = 0;) [/ T' I! N2 a1 F
/* Add into free pool */
4 ?# N( i) ?. p$ u9 b7 O: v OS_ENTER_CRITICAL(); /* Avoid race condition */
# H, ]* r, {: p1 M- }- Y: b! m p_stLog->p_stNext = s_pstFreeLog;
( O* b; M" C8 S' K s_pstFreeLog = p_stLog;
* T B8 C1 |5 E3 G# l( `: P; ], c OS_EXIT_CRITICAL();* c0 r# g+ J) U8 C) |7 A
return;# m7 ~( g3 Y7 Z* z) ]& _$ `
}5 { m$ _6 b+ X6 H/ t/ v% i
带日志记录功能的内存分配MallocExt()和内存释放FreeExt()函数:1 Q; W. S& l2 \
/*********************************************************
' y! W+ {$ ^+ u( z* Malloc Extension
% L$ w! F( S5 K8 [) _5 j) f/ z* Description : Malloc a block of memory and log it if need
5 @5 Y( p8 c4 G h; c5 ^) R$ }" v; e' U* Arguments : INT32S iSize size of desired allocate memory( j4 K; E7 w `4 r; J& u3 D
* Returns: void *NULL= failed, otherwise=pointer of allocated memory
; W% \' I+ Q$ l6 M$ {; d2 p* Notes :# ?' Z) C+ s& W& w2 q
**********************************************************/' z4 z4 w$ F4 `- _4 l# @% R
void *MallocExt(INT32S iSize)
4 T3 l+ O3 _+ j/ s6 L4 t( _{
3 U: k4 w6 q: l/ j7 Z3 P2 @! X ASSERT(iSize > 0);. K$ N! B- }! @8 p" Q
void *p_vAddr;3 r8 R8 r* _2 J2 E; b
p_vAddr = malloc(iSize);
( y* ~2 V5 F& v I6 s# V if (!p_vAddr): q0 m8 [8 o v- g+ U
{, U( b+ X/ K$ W0 i7 {- n: U
PRINTF("malloc failed at %s line %d.\r
`) M( t+ \9 N", __FILE__, __LINE__);
$ x& {* O+ {: u }
. m+ ?" a) V2 L# i. U4 Y! c& W, G else
& n3 i5 D5 \) ]; C; j- K {
3 f6 P, ?* V% I. W% p5 v% J #if (DMEM_DBG && DBG_VER)
. _& H9 g3 h1 S memset(p_vAddr, 0xA3, iSize); /* Fill gargage for debug */
/ A, m J0 y) z( o, c) Y! n5 O6 w1 N, Y LogDMem(p_vAddr, iSize); /* Log memory for debug */6 Y* R8 \5 P" q' r% }3 p
#endif
( ]4 f0 \, e: J' S" t7 T }3 a* C3 a* @$ B9 n+ I6 U3 r8 D' H
return p_vAddr; - T" g6 \* j$ s% `* {, j9 I. S
}
$ t9 A* ?* S0 R, g" S/**********************************************************
4 T# c. t7 }7 L! O9 n& J* Free Extension
& ?& t$ q( j9 \: z* Description : Free a block of memory and unlog it if need
5 a' B7 ?, ]) c* E Z* Arguments : void * p_vMem point to the memory by this pointer
7 m) R- v( h* T( \' b: R* Returns : void
; n _* _2 q" V5 w4 a. u* Notes :
0 p! t/ O t z d* \**********************************************************/% y R6 ?- p7 T5 x( S
void FreeExt(void *p_vMem)0 A% u& I9 H" M7 s1 I
{, \& A' y! m( }
ASSERT(p_vMem);
8 y) Q& H/ `3 j1 C1 \& l8 r, I free(p_vMem);
% F, S0 s- U, \; p5 T #if (DMEM_DBG && DBG_VER)7 ^4 s) z/ T0 t' o3 y* c
UnlogDMem(p_vMem); /* Remove memory from log */. f# H m* y" I. h
#endif
, s& N7 N+ m: ^, \. p8 ?3 V0 P return;
& r' ]7 N. y9 Z}3 g- O; P. p% W. V$ J9 |
% g% P6 L7 X% {4 B8 n8 K& g
原文:https://blog.csdn.net/jiangjunjie_2005/article-END-7 ?$ ~5 G" N$ x: q: N
往期推荐:点击图片即可跳转阅读3 d3 s6 C, y& X: c% ^! U \
tcypmv2piaj64020244812.jpg
( k6 `; l% [2 \1 x3 U! d
最近在画图,电源稳定性对嵌入式硬件设备来说,实在是太重要了!2 ~# K5 y ~2 a$ @ a% x
4unjps1ahtc64020244912.jpg
& a r% ^3 p& X
嵌入式设备能在LCD屏幕上显示中文,是基于什么原理?
: b, k% E, ]! L9 b; q
zogznx4bkjz64020245012.jpg
- k& M1 ^6 M0 w! v嵌入式软件,代码的可读性与可运行性,哪个更重要?" Z6 k: w: k) E7 a. v' a
我是老温,一名热爱学习的嵌入式工程师$ H* U# Q2 l4 r1 f4 _9 S
关注我,一起变得更加优秀! |
|