最近在使用ELDK(arm-linux-) u-boot 1.3.0 时候遇到到网上盛传的 malloc 返回指针为0的怪问题
(DL)malloc 调用流程为:
->malloc() //dlmalloc.c
->mALLOc() //dlmalloc.c
->malloc_extend_top() //dlmalloc.c
->sbrk() //board.c ----->mem_malloc_init() -------> CFG_MALLOC_LEN
即首次使用malloc时堆中的可用缓冲区字节数为0. 然后根据DLMALLOC 的算法会通过sbrk函数去往堆中添加内存(最多CFG_MALLOC_LEN bytes)。调试记录如下:
nf: malloc() nb=65544,bytes=65536
nf:remainder_size = -65544 bytes
nf:chunksize(top) = 0 bytes
nf:nb = 65544 bytes
nf: this is func malloc_extend_top()
nb = 65544
top_pad = 6291456 !!!!!!!!!!error
MINSIZE = 16
sbrk_size = 6357016
sbrk_size = 6357016
nf: calling sbrk(sbrk_size = 6357016 bytes)
nf:this is func sbrk() start, increment = 6357016 bytes
nf: sbrk return fail, 55555~~~~~
nf:this is func sbrk() start, increment = 4072 bytes
nf: malloc fail:(
从调试记录中可见top_pad 值异常,top_pad的声明以及解释如下:
static unsigned long top_pad = DEFAULT_TOP_PAD; // =0
/*
M_TOP_PAD is the amount of extra `padding' space to allocate or
retain whenever sbrk is called. It is used in two ways internally:
* When sbrk is called to extend the top of the arena to satisfy
a new malloc request, this much padding is added to the sbrk
request.
* When malloc_trim is called automatically from free(),
it is used as the `pad' argument.
In both cases, the actual amount of padding is rounded
so that the end of the arena is always a system page boundary.
The main reason for using padding is to avoid calling sbrk so
often. Having even a small pad greatly reduces the likelihood
that nearly every malloc request during program start-up (or
after trimming) will invoke sbrk, which needlessly wastes
time.
Automatic rounding-up to page-size units is normally sufficient
to avoid measurable overhead, so the default is 0. However, in
systems where sbrk is relatively slow, it can pay to increase
this value, at the expense of carrying around more memory than
the program needs.
*/
可见top_pad赋初值为0, 在malloc_extend_top() 中调用到的值却为6291456从而导致内存分配失败。尝试着仅仅将此值改为1024,1,2 等非零值则一切正常,真是奇怪!!!
debug 记录如下(top_pad = 1024):
nf: malloc() nb=65544,bytes=65536
nf:remainder_size = -65544 bytes
nf:chunksize(top) = 0 bytes
nf:nb = 65544 bytes
nf: this is func malloc_extend_top()
nb = 65544
top_pad = 1024 !!!correct
MINSIZE = 16
sbrk_size = 66584
sbrk_size = 66584
nf: calling sbrk(sbrk_size = 66584 bytes)
nf:this is func sbrk() start, increment = 66584 bytes
nf:this is func sbrk() start, increment = 3048 bytes
结论: 在使用denx 自带的 arm-linux-gcc 编译 u-boot 时候将dlmalloc.c 中 top_pad 赋值改成1024(或其他非0值)即可
避免malloc分配内存失败的问题。如下:
static unsigned long top_pad = 1024;//DEFAULT_TOP_PAD; // =0
但是此问题发生的root cause还需高手指点,本文只期望能够抛砖引玉^^