我有一个使用gcc-arm-none-eabi toolchanin编译的准系统臂控制器。 我注意到要求malloc()获得132个字节,这反过来导致malloc()两次调用sbrk(),首先要求大小为152 B,然后在返回之前要求4100 B.
在这种情况下,从sprintf()调用Malloc(),似乎每个格式化程序(%d,%f,...)都分配了自己的内存。重复使用一个标识符不会导致更多分配。当使用%f时,分配4100 B。
在这种情况下,4 kB不是问题。但我想知道它并没有要求另外类似的金额。malloc应该分配这么多吗?
我可以设置什么来阻止它吗?
我是否应该担心malloc可能会要求更多空间(没有理由)?
sbrk代码不是工具链提供的代码。 malloc被包裹,所以我可以看到会发生什么。
char *_cur_brk;
void *_sbrk_r(struct _reent *reent, ptrdiff_t diff)
{
void *_old_brk = _cur_brk;
monitor_printf("_sbrk_r called with size = %d. cur_brk = %p \t", diff, _cur_brk);
void * ptr;
ptr = __builtin_return_address(0);
monitor_printf("Called from %d: %p\t", 0, ptr );
monitor_printEOL();
extdiff = diff;
if ( (_cur_brk + diff ) > _HeapLimit ) {
sbrk_error += 1;
errno = ENOMEM;
monitor_printf(" failed, cur_brk=%d, HeapLimit=%d", _cur_brk, _HeapLimit);
monitor_printEOL();
return (void *)-1;
}
sbrk_error = 0;
_cur_brk += diff;
monitor_printf("return %p", _old_brk);
monitor_printEOL();
return _old_brk;
}
void * __wrap__malloc_r( struct _reent *reent, size_t size )
{
void * ret;
monitor_printf("wrap_malloc_r called with size = %d.", size);
monitor_printEOL();
ret = __real__malloc_r( reent, size );
return ret;
}
对malloc(132)的调用输出
wrap_malloc_r called with size = 132.
_sbrk_r called with size = 152. cur_brk = 0x20005f64 Called from 0: 0x801311b
return 0x20005f64
_sbrk_r called with size = 4100. cur_brk = 0x20005ffc Called from 0: 0x8013181
return 0x20005ffc
Memory allocated at 0x20005f70lling malloc(132)
感谢 /约翰
答案 0 :(得分:2)
"没有理由"这是一个大胆的主张,我相信它并不只是为了做到这一点。
然而,您应该做的是调查是否可以转移到更加嵌入式友好的标准库,这个库对内存更加谨慎。它似乎是你的堆分配代码,即malloc()
实现的罪魁祸首。
一个简单的猜测是malloc()
需要一些数据结构来跟踪分配,因为你(可能,记住这是一个猜测!)做第一次分配作为副作用vsnprintf()
,必须这样做才能跟踪它。
在当今更典型的桌面/服务器计算机平台上,4 KB的内存非常少,因此如果设计需要,则没有理由不进行分配。当然,在嵌入式领域,这不是真的。
就个人而言,我有vsnprintf()
的本地替换,它实现零堆分配。