C++ memory management

  Memory management is the most hated issue in C++, and it is also the most controversial issue in C++. C++ masters get better performance and greater freedom from it. Hate, but memory management is ubiquitous in C++, and memory leaks occur in almost every C++ program, so if you want to become a C++ master, you must pass the memory management level, unless you give up C++ and go to Java or . NET, their memory management is basically automatic, and of course you give up freedom and dominance over memory, as well as the superior performance of C++.

memory allocation method

  In C++, memory is divided into 5 areas, which are heap, stack, free storage area, global/static storage area and constant storage area.

(1) heap

  It is those memory blocks allocated by new, and their release is ignored by the compiler and controlled by our application. Generally, a new corresponds to a delete. If the programmer does not release it, the operating system will automatically recycle it after the program ends.

(2) stack

  When a function is executed, the storage units of local variables in the function can be created on the stack, and these storage units are automatically released when the function execution ends. The stack memory allocation operation is built into the processor's instruction set, which is very efficient, but the allocated memory capacity is limited.

(3) Free storage area

  It is the memory block allocated by malloc, etc., which is very similar to the heap, but it uses free to end its life.

(4) Global/static storage area

  Global variables and static variables are allocated to the same memory. In the previous C language, global variables were divided into initialized and uninitialized. In C++, there is no such distinction. They occupy the same memory area.

(5) Constant storage area

  This is a special storage area. They store constants and are not allowed to be modified.

1. Difference between heap and stack

(1) Management method

  For the stack, it is automatically managed by the compiler without our manual control;

  For the heap, the release work is controlled by the programmer, which is prone to memory leaks;

(2) Space size

  Generally speaking, under a 32-bit system, the heap memory can reach 4G of space. From this point of view, there is almost no limit to the heap memory;

  But for the stack, there is generally a certain space size, we can modify it;

(3) Growth direction

  For the heap, the growth direction is upward, that is, in the direction of increasing memory addresses;

  For the stack, its growth direction is downward, and it grows in the direction of decreasing memory addresses;

(4) Distribution method

  The heap is dynamically allocated, and there is no statically allocated heap;

  The stack has two allocation methods: static allocation and dynamic allocation. Static allocation is done by the compiler, such as the allocation of local variables.

  Dynamic allocation is allocated by the alloca function, but the dynamic allocation of the stack is different from that of the heap. His dynamic allocation is released by the compiler, and we do not need to implement it manually.

(5) Distribution efficiency

  The stack is a data structure provided by the machine system, and the computer will provide support for the stack at the bottom layer: allocating a special register to store the address of the stack, and pressing and popping out of the stack have special instructions to execute, which determines the high efficiency of the stack;

  The heap is provided by the C/C++ function library, and its mechanism is very complicated. For example, in order to allocate a piece of memory, the library function will search the heap memory according to a certain algorithm (for the specific algorithm, please refer to the data structure/operating system). If there is not enough space (probably due to too much memory fragmentation), it is possible to call system functions to increase the memory space of the program data segment, so that there is a chance to allocate enough memory, and then proceed to return. Obviously, the heap is less efficient than the stack

(6) Whether fragments can be generated

  For the heap, frequent new/delete will inevitably cause discontinuity of memory space, resulting in a large number of fragments and reducing the efficiency of the program;

  For the stack, this problem does not exist, because the stack is a first-in, last-out queue;

Control C++ memory allocation

  A common problem with using C++ in embedded systems is memory allocation, the loss of control over the new and delete operators.

  Ironically, the root of the problem is that C++ manages memory very easily and safely. Specifically, when an object is destroyed, its destructor can safely free the allocated memory.

  This is certainly a good thing, but the simplicity of this usage makes programmers overuse new and delete without paying attention to causality in an embedded C++ environment. Moreover, in embedded systems, due to memory constraints, frequent dynamic allocation of memory of indeterminate size will cause great problems and the risk of heap fragmentation.

  As a piece of advice, conservative use of memory allocation is a first rule of thumb in embedded environments.

  But when you have to use new and delete, you have to control memory allocation in C++. You need to replace the system memory allocator with a global new and delete, and overload new and delete on a class-by-class basis.

  A general way to prevent heap fragmentation is to allocate different types of objects from different fixed-size memory holders. Overriding new and delete for each class provides this control.

1. Overload the new and delete operators for a single class

class TestClass {
public:
    TestClass()
    {
        cout << "TestClass()" << endl;
    }
    ~TestClass()
    {
        cout << "~TestClass()" << endl;
    }
    void * operator new(size_t size);
    void operator delete(void *p);
};

void *TestClass::operator new(size_t size)
{
    cout << "operator new" << endl;
    void *p = malloc(size);
    return (p);
}

void TestClass::operator delete(void *p)
{
    cout << "operator delete" << endl;
    free(p); 
}

void main()
{
    TestClass *pTest = new TestClass;
    delete pTest;
    pTest = NULL;
}

2. Overload the new[] and delete[] operators for a single class

class TestClass {
public:
    TestClass()
    {
        cout << "TestClass()" << endl;
    }
    ~TestClass()
    {
        cout << "~TestClass()" << endl;
    }
    void * operator new[](size_t size);
    void operator delete[](void *p);
};

void *TestClass::operator new[](size_t size)
{
    cout << "operator new" << endl;
    void *p = malloc(size);
    return (p);
}

void TestClass::operator delete[](void *p)
{
    cout << "operator delete" << endl;
    free(p); 
}

void main()
{
    TestClass *pTest = new TestClass[5];
    delete[] pTest;
    pTest = NULL;
    return;
}

Pay special attention to the size of size_t nSize!
C++ new and delete implementation principle: https://blog.csdn.net/passion_wu128/article/details/38966581

Common memory errors and their countermeasures

1. Common memory errors

  (1) The memory allocation was unsuccessful, but it was used

  (2) Although the memory allocation is successful, it is referenced before it is initialized

  (3) The memory allocation is successful and has been initialized, but the operation has crossed the boundary of the memory

  (4) Forgot to release memory, causing memory leak

  (5) Release the memory but continue to use it

2. Countermeasures

  (1) After applying for memory with malloc or new, you should immediately check whether the pointer value is NULL. Prevent the use of memory with a NULL pointer value

  (2) Don't forget to assign initial values ​​to arrays and dynamic memory. Prevent uninitialized memory from being used as rvalue

  (3) Avoid out-of-bounds subscripts of arrays or pointers, especially beware of "more 1" or "less 1" operations

  (4) The application and release of dynamic memory must be paired to prevent memory leaks

  (5) After releasing the memory with free or delete, set the pointer to NULL immediately to prevent the generation of "wild pointer"

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324521608&siteId=291194637