Is there a reuse of virtual memory addresses in linux? - linux

I thought a little about virtual memory management, and came to the result that there can be two types of memory fragmentation. The first happens on the physical memory side where pages can not be freed because there are some bytes of it used. Mostly the last bytes will be freed sooner or later and then the physical memory page will become free again and is unmapped.
But what happens to the pointer (virtual address) returned by malloc. Let's assume a 32-bit system. The program "randomly" allocates and frees memory but there is never used more than some MByte. Let's assume further that the program will never free the memory in the order it is allocated. So the "top of heap" pointer can never be decreased as the free will never occur at the end of the heap. I assume that malloc has to map the memory always to the end of the heap memory space. This means the pointer value will increase with every call.
Earlier or later the returned pointer will reach the highest possible address (e.g. 0xffffffff) and it becomes impossible to further add memory while the system has enough free pages available as most pages have been freed. It is just a matter of the highest possible pointer value.
To solve this an algorithm would be needed that maintains unmapped address spaces and let them grow as more memory is beeing freed at the beginning or the end of the space. Is there an algorithm like this implemented by malloc?

I assume that malloc has to map the memory always to the end of the heap memory space.
This assumption is actually incorrect. Some implementations may keep multiple pools that different sizes of blocks are allocated from. (For instance, one common approach is a slab allocator, which keeps a separate pool for each size of block that the allocator will return.)
In any case, yes — all meaningful implementations of malloc() will track memory that has been freed and will reuse it when possible.

I had a short look at the slab allocator. This seems to be more related to memory page management used inside kernel. My question is related to the user space and the fact that whenever memory is allocated it needs to get an address in address space of the calling process's heap. What happens to this address space when it is limited as given in a 32-bit system.
It is clear that the system does not loose the memory at all. What I mean is that there is no address space left to get an address where the memory can be mapped while all memory at lower addresses has been freed and unmapped already.

Related

What happens to allocated pages that are mostly empty?

If a process initially has a number of pages allocated to it in the heap, but a lot of the data in the pages has been deallocated, is there some sort of optimization that the OS does to consolidate the data into one page so that the other pages can be freed?
In general, nothing happens, the heap will continue to have "holes" in it.
Since the (virtual) memory addresses known by a process must remain valid, the operating system cannot perform "heap compaction" on its own. However, some runtimes like .Net do it.
If you are using C or C++, all you can hope for by default is that malloc() will be able to reuse previously deallocated chunks. But if your usage pattern is "allocate a lot of small objects then deallocate half of them at random," the memory utilization will probably not decrease much from the peak.
If a process initially has a number of pages allocated to it in the heap
A process will not initially have pages allocates in a heap.
is there some sort of optimization that the OS does to consolidate the data into one page so that the other pages can be freed
The operating system has no knowledge of user heaps. It allocates pages to the process. What that process does with those pages is up to it (i.e., use them for a heap, stack, code, etc.).
A process's heap manager can consolidate freed chunks of memory. When this occurs, it is normally done to fight heap fragmentation. However, I have never seen a heap manager on a paging system that unmaps pages once they are mapped by the operating system.
The heap of a process never has holes on it. The heap is part of the data segment allocated to a process, that grows dynamically upwards to the top of the stack segment, basically with the use of the sbrk(2) system call (that fixes a new size to the data segment) so the heap is a continuous segment (at least in terms of virtual address space) of allocated pages. malloc(3) never returns the heap space (or part of it) to the system. See malloc(3) for info about this. While there are memory allocators that allow a process to have several heaps (by means of allocating new memory segments, by use of the mmap(2) system call) the segments allocated by a memory allocator are commonly never returned back to the system.
What happens is that the memory allocator reuses the heap space allocated with sbrk(2) and mmap(2) and manages memory for being reused, but it is never returned back to the system.
But don't fear, as this is handled in a good and profitable way by the system, anyway.
That should not affect the overall system management, except from the fact that it consumes virtual address space, and probably page contents will end in the swap device if you don't use them until the process references them again and makes the system to reload them from the swap device(s). If your process doesn't reuse the holes it creates in the heap, the most probable destination is for the system to move them to the swap device and continue reusing it for other processes.
At this moment, I don't know if the system optimices swap allocation by not swapping out zeroed pages, as it does, for example, with text segments of executables (they never go to a swap device, because their contents are already swapped off in the executable file ---this was the reason you couldn't erase in ancient unices a program executable, or the reason there's not need anymore to use the sticky bit in frequently used programs---) but I think it doesn't (and the reason is that it's most improbable the unused pages will be zeroed by the application)
Be warned only in the case you have a 15Gb single process' heap use in your system and 90% of heap use is not in use most of the time. But think better in optimising the allocation resources because a process that consumes 15Gb of heap while most of the time 90%+ is unused, seems to be a poor design. If you have no other chance, simply provide enough swap space to your system to afford that.

Preventing Linux kernel from taking allocated memory from a process

I want to allocate a large portion of memory using malloc() for an indefinite amount of time. I may touch the memory for a long time let say 1 minute. How do i prevent the kernel from taking that memory away from the process?
I can not re allocate that memory because it is being used by another device that is outside of the kernels control.
In the Linux, you can allocate memory in user space, such as with malloc or a mmap, pass it down to the kernel, and then in the kernel, obtain references to the memory with get_user_pages. This will prevent the pages from going away, and also allow them to be accessed from any address space as struct page * references (and requiring kmap and kunmap if CONFIG_HIGHMEM is in effect). These pages will not be contiguous physical memory, however, and they may not be in a suitable range for DMA.
Memory to be accessed by devices is usually allocated in the kernel (e.g. using kmalloc with GFP_DMA. For allocations larger than a page, kmalloc finds consecutive physical pages, too. Once obtained, kmalloc-ed memory can be mapped into user space with remap_pfn_range.

libc memory management

How does libc communicate with the OS (e.g., a Linux kernel) to manage memory? Specifically, how does it allocate memory, and how does it release memory? Also, in what cases can it fail to allocate and deallocate, respectively?
That is very general question, but I want to speak to the failure to allocate. It's important to realize that memory is actually allocated by kernel upon first access. What you are doing when calling malloc/calloc/realloc is reserving some addresses inside the virtual address space of a process (via syscalls brk, mmap, etc. libc does that).
When I get malloc or similar to fail (or when libc get brk or mmap to fail), it's usually because I exhausted the virtual address space of a process. This happens when there is no continuous block of free address, an no room to expand an existing one. You can either exhaust all space available or hit a limit RLIMIT_AS. It's pretty common especially on 32bit systems when using multiple threads, because people sometimes forget that each thread needs it's own stack. Stacks usually consume several megabytes, which means you can create only few hundreds threads before you have no more free address space. Maybe an even more common reason for exhausted address space are memory leaks. Libc of course tries to reuse space on the heap (space obtained by a brk syscall) and tries to munmmap unneeded mappings. However, it can't reuse something that is not "deallocated".
The shortage of physical memory is not detectable from within a process (or libc which is part of the process) by failure to allocate. Yeah, you can hit "overcommitting limit", but that doesn't mean the physical memory is all taken. When free physical memory is low, kernel invokes special task called OOM killer (Out Of Memory Killer) which terminates some processes in order to free memory.
Regarding failure to deallocate, my guess is it doesn't happen unless you do something silly. I can imagine setting program break (end of heap) below it's original position (by a brk syscall). That is, of course, recipe for a disaster. Hopefully libc won't do that and it doesn't make much sense either. But it can be seen as failed deallocation. munmap can also fail if you supply some silly argument, but I can't think of regular reason for it to fail. That doesn't mean it doesn't exists. We would have to dig deep within source code of glibc/kernel to find out.
1) how does it allocate memory
libc provides malloc() to C programs.
Normally, malloc allocates memory from the heap, and adjusts the
size of the heap as required, using sbrk(2). When allocating blocks of
memory larger than MMAP_THRESHOLD bytes, the glibc malloc()
implementation allocates the memory as a private anonymous mapping
using mmap(2). MMAP_THRESHOLD is 128 kB by default, but is adjustable
using mallopt(3). Allocations performed using mmap(2) are unaffected
by the RLIMIT_DATA resource limit (see getrlimit(2)).
And this is about sbrk.
sbrk - change data segment size
2) in what cases can it fail to allocate
Also from malloc
By default, Linux follows an optimistic memory allocation strategy.
This means that when malloc() returns non-NULL there is no guarantee
that the memory really is available.
And from proc
/proc/sys/vm/overcommit_memory
This file contains the kernel virtual memory accounting mode. Values are:
0: heuristic overcommit (this is the default)
1: always overcommit, never check
2: always check, never overcommit
Mostly it uses the sbrk system call to adjust the size of the data segment, thereby reserving more memory for it to parcel out. Memory allocated in that way is generally not released back to the operating system because it is only possible to do it when the blocks available to be released are at the end of the data segment.
Larger blocks are sometime done by using mmap to allocate memory, and that memory can be released again with an munmap call.
How does libc communicate with the OS (e.g., a Linux kernel) to manage memory?
Through system calls - this is a low-level API that the kernel provides.
Specifically, how does it allocate memory, and how does it release memory?
Unix-like systems provide the "sbrk" syscall.
Also, in what cases can it fail to allocate and deallocate, respectively?
Allocation can fail, for example, when there's no enough available memory. Deallocation shall not fail.

Heap size and position

I'm writing my own memory allocator. If my notion is right, there is kernel's addres space from zero to 1-GB, and user-space from 1 to 4, that contains different sections like: code, stack, data, heap and others.
Is it right, that heap section's size and position can't be changed during the program execution?
How can I get the size and the position?
All I need to do, after getting heap area, is allocate the memory at my discretion, isn't I?
Why do you worry about this?
If you're writing an allocator a-la libc, use sbrk and/or mmap to reserve memory from the kernel. You do not need to worry about where the heap is placed with neither of those system calls.
If you want to instrument libc's malloc/calloc/realloc, things are even simpler - just wrap them in your allocator functions.
Yes, the allocator effectively manages the heap by requesting memory from the kernel. Typically, as is the case with brk, its position lies after the end of the data segment, and it grows at increasing addresses (or allocates in multiples of page size with mmap, etc.)
The allocator manages the size; the position of the heap is not relevant as far as the allocator is concerned, but it's at the position of knowing it.
The allocator effectively requests memory from the kernel. Once it has that memory, it can distribute it to programs however it deems fit.
It is an allocator which defines a heap. If you have a custom allocator, and it determines that all memory clients have returned all memory, it is perfectly valid for it to delete its heap or create a new one to supply memory requests from.
Since the allocator itself defines the heap it should know its size and position. If what you are talking about is usurping the OS allocator's responsibility with your own allocator, you should only do this by using the OS allocator to obtain a block of memory then use that as the heap for your own allocator.
Again, once your allocator owns the memory block it may be used at your discretion. You cannot simply take memory which is managed by another allocator and in its free pool and use it without serious potential consequences.

What is a Memory Heap?

What is a memory heap ?
Presumably you mean heap from a memory allocation point of view, not from a data structure point of view (the term has multiple meanings).
A very simple explanation is that the heap is the portion of memory where dynamically allocated memory resides (i.e. memory allocated via malloc). Memory allocated from the heap will remain allocated until one of the following occurs:
The memory is free'd
The program terminates
If all references to allocated memory are lost (e.g. you don't store a pointer to it anymore), you have what is called a memory leak. This is where the memory has still been allocated, but you have no easy way of accessing it anymore. Leaked memory cannot be reclaimed for future memory allocations, but when the program ends the memory will be free'd up by the operating system.
Contrast this with stack memory which is where local variables (those defined within a method) live. Memory allocated on the stack generally only lives until the function returns (there are some exceptions to this, e.g. static local variables).
You can find more information about the heap in this article.
A memory heap is a location in memory where memory may be allocated at random access. Unlike the stack where memory is allocated and released in a very defined order, individual data elements allocated on the heap are typically released in ways which is asynchronous from one another. Any such data element is freed when the program explicitly releases the corresponding pointer, and this may result in a fragmented heap. In opposition only data at the top (or the bottom, depending on the way the stack works) may be released, resulting in data element being freed in the reverse order they were allocated.
Heap is just an area where memory is allocated or deallocated without any order. This happens when one creates an object using the new operator or something similar. This is opposed to stack where memory is deallocated on the first in last out basis.
It's a chunk of memory allocated from the operating system by the memory manager in use by a process. Calls to malloc() et alia then take memory from this heap instead of having to deal with the operating system directly.
You probably mean heap memory, not memory heap.
Heap memory is essentially a large pool of memory (typically per process) from which the running program can request chunks. This is typically called dynamic allocation.
It is different from the Stack, where "automatic variables" are allocated. So, for example, when you define in a C function a pointer variable, enough space to hold a memory address is allocated on the stack. However, you will often need to dynamically allocate space (With malloc) on the heap and then provide the address where this memory chunk starts to the pointer.
A memory heap is a common structure for holding dynamically allocated memory.
See Dynamic_memory_allocation on wikipedia.
There are other structures, like pools, stacks and piles.
Memory organization is divided into two parts: heap memory and stack memory.
Heap memory is the main working memory, lowest address is the starting address.
In stack memory, the flow of data is driven by bottom to up approach. Then the memory Arch is named as stack.
every running process has its own private fake virtual memory provided by the OS.
the OS can map this to physical memory at any point as long as it is available otherwise it will map to disk and swap as needed.
this virtual memory is logically divided into segments for organizing different kinds of data.
the code segment holds the executable instructions.
the data segment holds static data such as global or static variables.
the stack holds local data that is automatically managed by called and returning functions.
all of these segments are fixed size even the stack its just the portion used can grow or shrink and is reclaimed as functions returned.
the only segment that is not preallocated at app startup and fixed size is the heap.
the app can request from the OS at runtime new memory to be allocated and the OS will reserve a part of your apps virtual space and commit that to physical memory as needed.
the OS will return a pointer to that newly allocated heap memory and that pointer holds the base or starting address of the new block. that pointer sits on the stack and when that stack space is reclaimed your pointer will be no longer in scope and therefore you have no means of access to that block of memory. and if you dont tell the OS you are done with it so it can reclaim it that is just zombie memory sitting there with no means of access and if your app keeps requesting memory while never giving it back it will crash when the system runs out of memory. so it is important to free or at least pass the pointer to another pointer external to the scope it was defined in so you can maintain an interface to that memory allocated in heap space. i would suggest looking into virtual memory further and understanding segments.

Resources