A blog on Computer Science, Security, Programming, and more...

HeapSpray Blog » Programming » View Post

06
Mar
2015

Linux Memory Allocation and Forcing Memory Release

Written by Matt

The below is a terse explanation of how allocating memory with libc in Linux works. With libc is important, because you can allocate memory in straight assembly by just calling syscall and the below no longer applies. If you are curious as to how, here is an example for 64-bit Linux on x86-64 that allocates a 16MB page. You will need the NASM assembler:

extern printf

section .data

strQ: 
        db 'Current program data segment end address: %llX',0xA,0x00
strE: 
        db 'Size after brk +0x1000000: %llX',0xA,0x00

section .text

global main
main:
# call brk, store result on stack
mov rax, 12
xor rdi, rdi
syscall
push rax

# report end of program break
mov rdi, strQ
mov rsi, rax
call printf

# allocate 16MB of memory by adding 1024*1024*16 to the return of brk
mov rax, 12
pop rdi
add rdi, 0x1000000
syscall

# report new program break
mov rdi, strE
mov rsi, rax
call printf

# call exit
mov rax, 60
xor rdi, rdi
syscall
Assemble and link with:

nasm -f elf64 -o brk.o brk.s
ld -s -dynamic-linker /lib64/ld-linux-x86-64.so.2 -e main -lc -o brk brk.o
Example run:

$ ./brk       
Current program data segment end address: B73000
Size after brk +0x1000000: 1B73000

Almost all programs, though, regardless of language, use libc calls in Linux to allocate memory. Note that from the kernel's perspective, there is really no difference between the "heap" and the "stack". They are both stored in RAM, obviously, the pages are just tagged differently. You can get and modify the program's stack size with getrlimit() and setrlimit().

Linux's Memory Model

When you allocate memory on Linux, malloc() calls the system call brk(), which tells the kernel to set the "program break", i.e., the end of the program's data segment, which is essentially what determines the size of the "heap". Due to the fact that memory allocation works by pages, even if you free memory using free() it won't really be released unless what you've released is at the end of the program's data segment. In essence, if you free something at the start of the segment, and then malloc it again, libc will simply return that block back to you instead of requesting a new page of memory from the kernel.

Beyond the above mechanics, even if you do free data at the end of the program's segment, it's not guaranteed that said memory will actually be released back to the kernel. Many libc implementations instead often decide to defer that release for performance reasons, so that if you malloc something a short while later it doesn't need to bother the kernel and can just return the block it kept allocated.

Forcing Memory Release

There are times though when you really want to release memory to the OS as soon as possible (such as if you're working on an embedded system with very limited memory), without messing around with brk and sbrk and potentially destroying malloc's internal memory map. For those cases, the library call malloc_trim() does just that, it releases the maximum amount of pages it can if called with the argument 0. It "trims" space at the end of the data segment, and the argument is the amount of space to leave "left" after the last still allocated/in use block. So if called with 0, it forces a release of all memory that is no longer in use.

The only downside is that there is no real guarantee that this is even implemented as it's not a standard library function, and sometimes it's poorly implemented and not thread safe. Using this on a system with large amounts of memory will only serve to make your program slower, but it is a useful function to know when you're working on a system with very limited resources and you want to make sure you don't push the rest of the memory into SWAP, and that your program doesn't accidentally get killed by the OS for having a virtual memory size that's too big.

  • Name and Email fields are optional
  • Your email will not be public, only the administrator can see it
  • You are rate limited to one comment for every 10 minutes