6.28 Memory allocation/management learning summary

1. Verify system memory allocation mechanism through program

1. Experiment:

Two char pointers apply for 100 and 102 bytes in memory successively. How many bytes of memory space will they actually occupy?

If two char pointers continuously apply for 200 bytes in memory, how many bytes of memory space will they actually occupy?

2. Program and running results:

#include<iostream>
#include <unistd.h>
#include <malloc.h>
using namespace std;

int main(){
    char* p1 = (char *)malloc(100);
    char* p2 = (char *)malloc(102);
    cout << malloc_usable_size(p1) << endl;
    cout << malloc_usable_size(p2) << endl; 
    cout << static_cast<void *>(p1) << endl;   
    cout << static_cast<void *>(p2) << endl;  
    free(p1);
    free(p2);
    return 0;
}

The actual occupied sizes of the two pointers run out are both 104 bytes.

Through further experiments, it was found that the allocated memory size and the actual occupied memory have the following relationship:

allocated memory size Actual memory size occupied
0 ~ 24 24
25 ~ 40 40
41 ~ 56 56
... ...
89~104 104
... ...
#include<iostream>
#include <unistd.h>
#include <malloc.h>
using namespace std;

int main(){
    char* p1 = (char *)malloc(200); 
    printf("p1 = %p\n", p1);
    char* p2 = (char *)malloc(200); 
    printf("p2 = %p\n", p2);

    printf("p1内存起始地址:%x\n", p1);
    printf("p2内存起始地址:%x\n", p2);

    printf("使用cat /proc/%d/maps查看内存分配\n",getpid()); 
    getchar();

    free(p1);
    p1 = NULL;
    free(p2);
    p2 = NULL;
    return 0;
}

In fact, in addition to the 200 bytes of available space, it also consumes space in the memory control block. The memory starting address returned to user mode by malloc is 16 bytes more than that of the process. The extra 16 bytes store the description information of the memory block.

3. Analysis of experimental results

        From the above experimental results, it can be concluded that under a 64-bit system, the size of the available memory we apply for will be 16x + 8, and the allocated memory size will correspond to the same actual occupied memory size in each interval. So what is the purpose of such memory allocation? By consulting relevant information, it can be concluded that this is done to align the memory and thereby improve efficiency. In addition to the available space, space in the memory control block is also consumed . Therefore, the actual memory size allocated by malloc will be larger than the size we need, and is determined by both byte alignment and memory control block.

2. Memory alignment

1 Introduction

        Memory is used to temporarily store calculation data in the CPU and data exchanged with external memories such as hard disks. Memory is the bridge between external memory and CPU, and is a very important part of the computer.

        When executing a program, the input device first issues an operation instruction to the CPU. After the CPU receives the operation instruction, the corresponding program in the hard disk will be directly loaded into the memory. Then, the CPU performs an addressing operation on the memory, translates the instructions loaded into the memory, and sends operation signals to the operation controller to implement the execution of the program. Programs in computers run in memory, so the performance of memory will affect the performance of the computer.

2. What is memory alignment? Why do we need memory alignment?

        Memory alignment is to arrange various types of data in space according to certain rules, rather than arranging them one after another in order. This is called memory alignment. Memory alignment refers to first address alignment. Here’s why:

(1) Performance considerations:

       Each time the CPU accesses the memory, it is accessed in units of word length, so the memory should be aligned. If the unaligned memory is accessed, the CPU needs to perform two access operations. Therefore, memory alignment can improve performance.

        From a hardware perspective, because the memory module is designed in this way, the banks in the memory chip are parallel. A memory is composed of many chips, and each chip is composed of 8 banks. A bank is a two-dimensional matrix, and each element in the matrix stores one byte.

        In the application, the 8 consecutive bytes in the memory appear to be continuous, but they are not physically continuous. This is because the 8 banks can actually work in parallel. When the memory is aligned, work once and put the obtained data together to get 8 consecutive bytes of addresses in the memory, thereby improving IO efficiency.

(2) Platform considerations:

        The CPU on some hardware platforms can access any data at any address, but some can only access data at a specific address, otherwise a hardware exception will be thrown. Because different hardware platforms have certain differences, portability can be achieved by aligning the allocated memory during the compilation phase.

3. What happens if the memory is not aligned?

        Unaligned memory accesses will have different effects in different architectures: some computers can handle unaligned accesses transparently, but this will greatly reduce efficiency; some computers may generate exceptions, which can be corrected by calling an exception handler; However, some computers generate exceptions but cannot correct the errors; other computers have no way to handle unaligned accesses and directly read incorrect memory addresses, resulting in code vulnerabilities that are difficult to find.

3. Memory management

1、malloc

        When malloc applies for memory, it allocates virtual memory. There are two ways to apply for memory from the operating system:

(1) Allocate memory from the heap through the brk() system call

(2) Allocate memory in the file mapping area through the mmap() system call

        A threshold is defined by default in the malloc() source code: (Thresholds defined by different glibc versions are also different)

  • If the memory allocated by the user is less than 128 KB, apply for memory through brk();

  • If the memory allocated by the user is greater than 128 KB, apply for memory through mmap();

        The essence of the malloc function is a free linked list that connects available memory blocks into a linked list. Sometimes it is also implemented with a doubly linked list. Each memory block has a header called memory control block mem_control_block. The MCB records some information about the memory block, such as the pointer of the next allocated block, the length of the current allocated block, and whether the current allocated block is available.

typedef struct mem_control_block
{
    size_t size;  //本块大小
    bool free;  //空闲状态
    struct mem_control_block *next;  //后块指针
}MCB;
MCB *g_top = NULL;  //栈顶指针

        When malloc allocates, it will search the free linked list. In order to ensure the continuity of the memory allocated to the program, according to the memory matching principle, it finds a free memory block that can meet the required space, then allocates this part of the space, and returns this part of the space. the starting pointer. The pointer returned by malloc is the starting pointer of the available space, which is the address following the header. The header of the above allocated block is invisible to the program. If a memory block that meets the conditions cannot be found, it will apply to the operating system for extended heap memory. The operating system will allocate new enough memory and push its control block onto the linked list stack.

        This is equivalent to using pooling technology to implement a memory pool. First apply for appropriate memory space from the operating system, and then manage it yourself. If it is not enough to meet actual needs, apply to the operating system again. There is no need to make a system call every time malloc is used, which is relatively expensive and will affect the performance of the system.

        The system functions brk() and sbrk() are used to adjust the amount of memory allocated to the data segment of the process. brk and sbrk maintain a pointer on the heap at the bottom and manage dynamic memory (heap) in an incremental manner. Typically, these functions are called from a larger memory management library function such as malloc. sbrk(x) function, x is the application space size, 0 does not apply for space, greater than 0 applies for space, less than 0 releases space. And brk(addr) needs to move the top pointer of the heap backward to the address addr. The size of the moving space is the amount of space applied for.

2、free

    freeThe memory block will be re-inserted into the free list and the free status of the memory head will be modified. freeIt only accepts a pointer, but can release the appropriate size of memory. This is because the size of the allocated area is saved at the beginning of the area.

        When malloc applies for memory, there are two ways to apply for heap memory from the operating system: 1. Allocate memory from the heap through the brk() system call; 2. Allocate memory in the file mapping area through the mmap() system call. For the memory applied for using the first method, the heap memory still exists and is not returned to the operating system, but put back into the memory pool; the memory applied for using the second method will be returned to the operating system.

Reference article:

Detailed explanation of memory alignment_Sunshine-Song's Blog-CSDN Blog

Take you to deeply understand the underlying principles of memory alignment - Zhihu

Memory Management (6): Understand the implementation principles of malloc and free in one article - Zhihu

Guess you like

Origin blog.csdn.net/qq_44189622/article/details/131419114