joing
joing

Reputation: 139

Why does malloc ask for unreasonable amout of memory from sbrk. what can prevent it?

I have a barebone arm controller compiled with the gcc-arm-none-eabi toolchanin. I notice that asking malloc() for 132 bytes which in turn causes malloc() to call sbrk() twice, first asking for size 152 B and next asking for 4100 B before returning.

Malloc() is in this case called from sprintf(), and it seem that each formatter (%d, %f, ...) allocates its own memory. Repeted use of one identifier does not result in more allocation. It is when %f is used that the 4100 B is allocated.

4 kB is in this case not a problem. But I would like to know that it does not ask for another similar amount.

The sbrk code is not the one provided from the toolchain. malloc is wrapped so I can see what happens.

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;
}

output of call to 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)

thanks /johan

Upvotes: 3

Views: 388

Answers (1)

unwind
unwind

Reputation: 399833

"Without reason" is a bold claim, I'm sure it's not doing it just to be mean.

What you should do, however, is investigate if you can move to a more embedded-friendly standard library, one that is more careful with memory. It seems its your heap allocation code, i.e. the malloc() implementation that's the culprit.

One simple guess is that malloc() needs some data structure to keep track of the allocations, and since you're (probably, remember this is a guess!) doing the first allocation as a side-effect of vsnprintf(), it has to do that in order to track it.

On more typical desktop/server computer platforms of today, 4 KB is very little memory so no reason to not do the allocation if it's needed by the design. In the embedded space, of course, that's not true.

Personally, I have a local replacement for vsnprintf() that does zero heap allocations.

Upvotes: 2

Related Questions