为什么malloc要求sbrk提供不合理的记忆。什么能阻止它?

时间:2016-09-23 10:58:14

标签: c gcc embedded malloc heap-memory

我有一个使用gcc-arm-none-eabi toolchanin编译的准系统臂控制器。 我注意到要求malloc()获得132个字节,这反过来导致malloc()两次调用sbrk(),首先要求大小为152 B,然后在返回之前要求4100 B.

在这种情况下,从sprintf()调用Malloc(),似乎每个格式化程序(%d,%f,...)都分配了自己的内存。重复使用一个标识符不会导致更多分配。当使用%f时,分配41​​00 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)

感谢 /约翰

1 个答案:

答案 0 :(得分:2)

"没有理由"这是一个大胆的主张,我相信它并不只是为了做到这一点。

然而,您应该做的是调查是否可以转移到更加嵌入式友好的标准库,这个库对内存更加谨慎。它似乎是你的堆分配代码,即malloc()实现的罪魁祸首。

一个简单的猜测是malloc()需要一些数据结构来跟踪分配,因为你(可能,记住这是一个猜测!)做第一次分配作为副作用vsnprintf(),必须这样做才能跟踪它。

在当今更典型的桌面/服务器计算机平台上,4 KB的内存非常少,因此如果设计需要,则没有理由不进行分配。当然,在嵌入式领域,这不是真的。

就个人而言,我有vsnprintf()的本地替换,它实现零堆分配。