【问题标题】:Why does malloc ask for unreasonable amout of memory from sbrk. what can prevent it?为什么 malloc 向 sbrk 请求不合理的内存量。什么可以防止它?
【发布时间】:2017-02-01 05:10:23
【问题描述】:

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

Malloc() 在这种情况下是从 sprintf() 调用的,似乎每个格式化程序 (%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)

谢谢 /约翰

【问题讨论】:

  • 为什么你会在裸机微控制器上使用 malloc?这没有任何意义——ARM 不是 PC。 Read this.
  • @Lundin:如今的微控制器可以拥有比最初的 IBM PC 更多的内存。您提供的链接指的是一个微控制器,malloc 确实没有意义,但您不能只是假设在这里加入也是如此。
  • @joing:这是一致的,还是仅在第一次通话时? malloc 可能会在第一次调用时设置一个 4kB 的簿记页面
  • @MSalters 内存量并不是它没有意义的原因。缺乏多进程桌面操作系统是。
  • @MSalters 不使用基于堆的动态内存分配的另一个原因是碎片。一个打算运行数月甚至数年的系统必须具有可预测的内存行为。

标签: c gcc embedded malloc heap-memory


【解决方案1】:

“无缘无故”是一个大胆的主张,我敢肯定这不是为了刻薄。

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

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

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

就个人而言,我有一个 vsnprintf() 的本地替代品,它执行零堆分配。

【讨论】:

  • 我想本地替换 vsnprintf 会很好。真正让我烦恼的是,当第一次真的应该足够时,对 sbrk 的双重调用。所以另一种解决方案是重写 malloc。
猜你喜欢
  • 2014-12-29
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-08
  • 1970-01-01
  • 2020-08-24
相关资源
最近更新 更多