Memory Allocation in linux: mmap, munmp, brk, mmapbrk
Linux virtual memory management has several key concepts:
1. Each process has an independent virtual address space. The virtual address accessed by the process is not a real physical address;
2. The virtual address can be mapped to the physical address through the page table on each process (in the kernel virtual address space of each process) to obtain the real physical address;
3. If the physical address corresponding to the virtual address is not in the physical memory, the page is interrupted, the physical address is allocated, and the page table of the process is updated. If the physical memory is exhausted, some pages are removed to the physical disk based on the memory replacement algorithm.
Based on the above understanding, the following analysis is made:
I. How is the virtual address space distributed in Linux?
Linux uses virtual address space, which greatly increases the addressing space of processes, from low addresses to high addresses:
1. Read-Only segment: this part of space can only be read and cannot be written. (including: code segment and rodata segment (C constant string and # constant defined by define ))
2. Data Segment: space for saving global and static variables;
3. Heap: the dynamic memory that we usually call. Most of malloc/new comes from this. The heap top position can be dynamically adjusted using the brk and sbrk functions.
4. File ing area: memory mapped to physical space, such as dynamic library and shared memory, is generally the virtual address space allocated by the mmap function.
5. STACK: it is used to maintain the context space of function calls. Generally, the value is 8 MB, which can be viewed through ulimit-s.
6. kernel virtual space: memory area invisible to user code, managed by the kernel (page tables are stored in the kernel virtual space ).
It is a typical virtual address space distribution of 32-bit Systems (from "understanding computer systems").
The 32-bit system has 4 GB address space ::
0x08048000 ~ 0 xbfffffff is the user space, 0xc0000000 ~ 0 xffffffff is the kernel space, including kernel code and data, and process-related data structures (such as page tables and kernel stacks. In addition, % esp executes the stack top and changes to the lower address direction; brk/sbrk function controls the heap top _ edata changes to the higher address direction.
What is the result of a 64-bit system? Does the 64-bit system have 2 ^ 64 address space?
In fact, the virtual address space division of the 64-bit system has changed:
1. The address space is not 2 ^ 32 or 2 ^ 64, but generally 2 ^ 48. Because there is no such large addressing space as 2 ^ 64, too much space will only lead to a waste of resources. 64-bit Linux generally uses 48 bits to represent virtual address space, and 40 bits to represent physical addresses,
This can be viewed through/proc/cpuinfo
Address sizes: 40 bits physical, 48 bits virtual
2. 0x00000000000000000000 ~ 0x00007fffffffff indicates the user space. 0xffffff800000000000 ~ 0 xffffffffffffff indicates the kernel space. A total of 256 TB (2 ^ 48) addressing space is provided.
These two intervals are characterized by 47th bits and 48-bit ~ 63 bits are the same. If these bits are 0, they represent the user space; otherwise, they represent the kernel space.
3. the user space from low address to high address is still read-only, data segment, heap, file ing region and stack;
Ii. How does malloc and free allocate and release memory?
How do I view the number of page breaks in a process?
Run the ps-o majflt and minflt-C program commands.
Majflt indicates major fault, the Chinese name is "big error", minflt indicates "minor fault", and the Chinese name is "small error.
These two values indicate the number of page-missing interruptions that have occurred since a process was started.
What operations are performed after a page is interrupted?
When a process suffers a page disconnection, the process will be in the kernel state and perform the following operations:
1. Check whether the virtual address to be accessed is legal
2. Find/allocate a physical page
3. Fill in the physical page content (read the disk or directly set it to 0, or do nothing)
4. Establish a ing relationship (from a virtual address to a physical address)
Re-execute the command with a page disconnection
If you need to read the disk in step 1, the page Disconnection will be majflt; otherwise, it will be minflt.
Principle of Memory Allocation
From the operating system perspective, there are two ways to allocate memory for processes: brk and mmap ).
1. brk pushes the highest address pointer _ edata of the data Segment (. data) to the high address;
2. mmap finds an idle virtual memory in the virtual address space of the process (in the middle of the heap and stack, called the place of the file ing area.
Both methods are allocated with virtual memory instead of physical memory. When you access the allocated virtual address space for the first time, a page disconnection occurs. The operating system allocates physical memory and establishes a ing between the virtual memory and physical memory.
In the standard C library, the malloc/free function is provided to allocate and release the memory. The two functions are called by brk, mmap, and munmap systems at the underlying layer.
The following example illustrates the principle of memory allocation:
Scenario 1: malloc memory less than kb. Use brk to allocate memory and push _ edata to the high address (only virtual space is allocated and does not correspond to physical memory (so no Initialization is made ), when data is read/written for the first time, a page disconnection occurs in the kernel. The kernel allocates the corresponding physical memory and establishes a ing relationship between the virtual address space. For example:
1. The initial layout of the (virtual) memory space of a process during startup is shown in 1.
Among them, the mmap memory ing file is in the middle of the heap and stack (such as libc-2.2.93.so, other data files, etc.), for the sake of simplicity, the memory ing file is omitted.
_ Edata pointer (defined in glibc) points to the highest address of the Data Segment.
2. After the process calls A = malloc (30 K), the memory space is 2:
The malloc function calls the brk system and pushes the _ edata pointer to the high address for 30 K to complete virtual memory allocation.
You may ask: As long as _ edata + 30 k is allocated to the memory?
The fact is that _ edata + 30K only completes the allocation of virtual addresses. The memory of A still does not correspond to physical pages. When the process reads and writes the memory of A for the first time, when A page disconnection occurs, the kernel allocates A physical page corresponding to the memory. That is to say, if malloc is used to allocate the content of A and never access it, the physical page corresponding to A will not be allocated.
3. After the process calls B = malloc (40 K), the memory space is 3.
Scenario 2: Use mmap to allocate memory with malloc greater than kb, and find an idle memory allocated between the heap and stack (corresponding to the independent memory and initialized to 0), for example:
4. After the process calls C = malloc (200 K), the memory space is 4:
By default, the malloc function allocates memory. If the request memory is greater than 128 KB (which can be adjusted by the M_MMAP_THRESHOLD option), it does not push _ edata pointer, but is called by the mmap system, allocate a virtual memory from the middle of the heap and stack.
This is mainly because ::
The memory allocated by brk can be released only after the High-address memory is released. (For example, before B is released, A cannot be released. This is why memory fragments are generated, the following figure shows when the compression occurs. The memory allocated by mmap can be released separately.
Of course, there are other advantages and disadvantages. If you are interested, you can check the malloc code in glibc.
5. After the process calls D = malloc (100 K), the memory space is 5;
6. After the process calls free (C), the virtual memory corresponding to C is released together with the physical memory.
7. After the process calls free (B), 7 is shown:
The virtual memory and physical memory corresponding to B are not released, because there is only one _ edata pointer. If we push back, what should we do with D memory?
Of course, the memory of B can be reused. If another 40 k request is made at this time, malloc may return the memory of B.
8. process calls after free (D), as shown in Figure 8:
B and D are connected to form a K idle memory.
9. By default:
When the free memory of the maximum address space exceeds 128 K (which can be adjusted by the M_TRIM_THRESHOLD option), the memory compression operation (trim) is executed ). When the last step is free, the maximum address idle memory exceeds 128 kb, so the memory is reduced, as shown in figure 9.
Iii. Since the memory brk and sbrk In the heap cannot be directly released, why not use mmap to allocate all resources, and the munmap can be directly released?
Since fragments in the heap cannot be directly released, this may cause "Memory leakage". Why does malloc not all use mmap (the memory allocated by mmap can be free through munmap, real release )? Instead, mmap is used only for memory larger than 128 kb?
In fact, the sbrk, mmap, and munmap interfaces used by processes to apply for and release address spaces from the OS are system calls, and frequent system calls consume system resources. In addition, when the memory requested by mmap is munmap, re-applying will cause more page missing interruptions. For example, when mmap is used to allocate 1 M space, the first call results in a large number of page-missing interruptions (1 M/4 K times). When munmap is used to allocate 1 M space again, a large number of page-missing interruptions will occur again. Page disconnection is a kernel action that causes a high CPU consumption in the kernel state. In addition, if you use mmap to allocate a small amount of memory, it will lead to more fragments of the address space and a greater management burden on the kernel.
At the same time, the heap is a continuous space, and the fragments in the heap are not returned to the OS. If the fragments can be reused, re-accessing the memory may not cause any system call or page disconnection, this will greatly reduce CPU consumption. Therefore, the malloc Implementation of glibc fully considers the differences between sbrk and mmap behavior and their advantages and disadvantages. By default, a large block of memory (128 k) is allocated to use mmap to obtain the address space, you can also modify this critical value through mallopt (M_MMAP_THRESHOLD.
4. How can I view the page disconnection information of a process?
You can run the following command to view the page disconnection information:
Ps-o majflt, minflt-C
Ps-o majflt, minflt-p
Among them: majflt indicates major fault, which indicates a large error;
Minflt indicates minor fault, indicating a small error.
These two values indicate the number of page-missing interruptions that have occurred since a process was started.
The differences between majflt and minflt are ::
Majflt indicates that the disk needs to be read and written. It may be because the page corresponding to the memory needs to be loaded to the physical memory in the disk, or because the physical memory is insufficient at this time, some physical pages need to be removed to the disk.
V. C language memory allocation and malloc
C language and Memory Allocation Method
(1) distribution from the static storage area. The program has been allocated when it is compiled, and the program exists throughout the entire runtime. For example, global variables and static variables.
(2) create a stack. When a function is executed, the storage units of local variables in the function can be created on the stack. When the function is executed, these storage units are automatically released. Stack memory allocation
It is highly efficient to calculate the instruction set built into the processor, but the allocated memory capacity is limited.
(3) allocate from the stack, also known as dynamic memory allocation. When the program runs, it uses malloc or new to apply for any amount of memory. The programmer is responsible for releasing the memory with free or delete. The lifetime of the dynamic memory is determined by us. It is very flexible to use, but it has the most problems.
Functions related to memory application in C language include alloc, calloc, malloc, free, realloc, and sbrk. here, alloc applies for memory from the stack, so it does not need to be released. the memory allocated by malloc is located in the heap and does not initialize the memory content. Therefore, basically, after malloc, call the memset function to initialize the memory space. calloc will initialize this part of memory, set to 0. while realloc adjusts the memory size applied for by malloc. the Applied memory needs to be released using the function free. sbrk increases the data segment size;
Malloc, calloc, and free are basically implemented by the C function library and have nothing to do with OS. the C function library uses a certain structure to store the current amount of available memory. if the malloc size of the program exceeds the reserved space in the library, the brk system call will be called to increase the available space and then the space will be allocated. when free, the released memory is not immediately returned to the OS, but stored in the internal structure. for example, brk is similar to a wholesale database, where a large memory size can be applied to the operating system at one time, while functions such as malloc are similar to retail, meeting the runtime requirements. this mechanism is similar to buffering.
The reason for using this mechanism: system calls cannot support memory allocation of any size (some system calls only support applying for memory of a fixed size and its multiples. In this case, the allocation of small memory will result in a waste; the system call request memory is expensive, involving the conversion of user and core states.
Both the functions malloc () and calloc () can be used to allocate dynamic memory space, but the two are slightly different.
In Linux, when a program is loaded into memory, the kernel creates code segments, data segments, and stack segments for the user's process address space. The idle areas between data segments and stack segments are used for dynamic memory allocation.
The member variables start_code and end_code in the kernel data structure mm_struct are the start and end addresses of the Process Code segment, start_data and end_data are the start and end addresses of the process data segment, and start_stack is the start address of the process stack segment, start_brk is the starting address for dynamic memory allocation of processes (the starting address of the heap), and a brk (the last address of the heap) is the ending address for dynamic memory allocation.
The basic function of dynamic memory allocation in C language is malloc (), and the basic implementation in Linux is called through the brk System of the kernel. Brk () is a very simple system call, but simply changes the brk value of the member variable of the mm_struct structure.
Mmap system calls enable more useful dynamic memory allocation, which can map all or part of a disk file to the user space, the read/write operation of a process changes to the read/write memory operation. The do_mmap_pgoff () function in the linux/mm/mmap. c file is the core of mmap system calling implementation. Do_mmap_pgoff () Code only creates a vm_area_struct structure and assigns the file structure parameter to its member variable m_file, without actually loading the file content into the memory.
One of the basic concepts of Linux memory management is that physical ing of an address is established only when an address is actually accessed.