[C++]– Detailed explanation of memory management new and delete

Hits: 0

Table of contents

1. C/C++ memory distribution

Two, C language dynamic memory management method

3. The reason why C++ uses new and delete

Fourth, C++ dynamic memory management method

1.new and delete

5. Memory leaks

1. C/C++ memory distribution

C/C++ [memory] is divided into 6 areas:

(1) Kernel space stores kernel code and environment variables

(2) The stack (also called the stack) stores non-static local variables/function parameters/return values, etc. The stack grows downward.

(3) The memory mapped segment is an efficient I/O mapping method for loading a shared dynamic memory library. Users can use the system interface to create shared memory for inter-process communication.

(4) The heap is used for dynamic memory allocation when the program is running, and the heap grows upward.

(5) The data segment stores global data and static data.

(6) The code segment stores executable code/read-only constants.

As shown below:

Two, C language dynamic memory management method

For a detailed introduction to C language dynamic [memory management] malloc, calloc, realloc, and free, please refer to the article C language – detailed explanation of dynamic memory management

3. The reason why C++ uses new and delete

new and delete are operators for C++ to apply and release space to memory.  Why does C++ use new and delete?

  1. The inconvenience of using malloc, calloc, realloc, and free management in C language is:

(1) Manually applying for memory requires manually calculating the size of the number of bytes

(2) Cast the return value type void *, otherwise it cannot be dereferenced

(3) Whether the memory application is successful or not, the return value needs to be judged empty

(4) Need to include header file

  1. The use of new and delete will process custom types:

(1) new will call the [constructor] new will call the [constructor] to initialize the class object

(2) delete will call the [destructor] delete will call the [destructor] to clean up resources

Fourth, C++ dynamic memory management method

1.new and delete

(1) There is no difference between new/delete and malloc/free on built-in types:

①Apply and release a single space, use new and delete

②Apply and release continuous space, use new[] and delete[]

# include <stdlib.h> 
int  main ()
 {
     //Operate built-in types

    //1. Apply for a single int object 
    int * p1 = ( int *) malloc ( sizeof ( int ));
     free (p1);

    int * p2 = new  int ; //int* p2 = new int(10); Allocate a single int object and initialize it to 10 
    delete p2;

    //2. Apply for an int array of 10 elements 
    int * p3 = ( int *) malloc ( sizeof ( int ) * 10 );
     free (p3);

    int * p4 = new  int [ 10 ];
     delete [] p4; //The custom type array delete must bring [], otherwise it will not match, and the program will terminate unexpectedly

    return 0;
}

C++11 supports array initialization with {}:

int* p5 = new int[5]{1,2,3,4,5};
delete[] p5;

(2) The operations of new/delete and malloc/free on custom types are different:

① malloc/free operations on custom types will only open space / release space

②The new operation of the custom type will open space + initialization, and the delete operation of the custom type will call the destructor to clean up + release the space

#include<iostream>
#include<stdlib.h>
using namespace std;

struct ListNode
{
    ListNode* _next;
    ListNode* _trans;
    int _val;

    ListNode( int val = 0 )
        : _next(nullptr)
        , _prev(nullptr)
        , _with
    {
        cout << "this.val =" << val << endl;
    }

    ~ListNode()
    {
        cout << "~ListNode()" << endl;
    }
};

int main()
{
    struct ListNode* n1 = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* n2 = new ListNode;

    free(n1);
    delete n2;

    return 0;
}

F10 monitoring, after walking 28 lines, the new operation is executed, and it is found that the 3 member variables of n1 malloc are random values, and the 3 member variables of n2 new have been initialized, so new will not only open space, but also call custom types The constructor to initialize: 

After finishing line 31, execute the delete operation, find that the content of the destructor is printed, and call the destructor:

Therefore, C++ not only opens space but also initializes, not only frees space but also cleans up resources.

Summarize:

(1) C++ If you apply for space for a built-in type, there is no difference between malloc and new

(2) If C++ applies for space for a custom type, the difference is very big:

①new sum is to open space + initialization, delete is to destruct and clean up + release space

② malloc is only to open space, free is only to release space

Suggestion: In C++, whether it is a built-in type or a custom type application release, try to use new and delete as much as possible

How do I request 4GB of space on the heap? Execute the following code on a 32-bit machine, the program will crash, because 2^32=102410241024*4, the 32-bit machine is only 4G in total. According to the C++ memory distribution, the kernel space occupies 1G, and the remaining 5 areas occupy a total of 3G, so the 32-bit platform can apply for less than 4GB of memory space.

void* p1 = malloc(1024 * 1024 * 1024 * 4);
cout << p1 << endl;

However, on VS go to Project – Project Properties – Configuration Manager – select x64 platform:

At this time, the 64-bit machine has a total of 2^64, which is about 16 billion GB, which is much larger than 4G. The 4G space was successfully applied for, but this 4G is actually virtual:


Definition: operator new and operator delete are global functions provided by the system, new calls the operator new global function at the bottom layer to apply for space, and delete uses the operator delete global function at the bottom layer to release the space, they are not overloads of new and delete.

The difference from malloc: the usage of operator new and operator delete is the same as that of malloc and free. The functions are to apply for free space on the heap, but the processing method of failure is different. malloc fails and returns NULL, and operator new fails and throws abnormal.

Use new to apply for space and initialize the custom type ListNode: new will call the operator new function and constructor, operator new will call malloc and fail to throw an exception mechanism, so both new and operator new will throw an exception if the application fails:

As can be seen from the above figure, new does not directly call malloc, but calls operator new. Because operator new is encapsulated, the return value will be reported directly if the malloc application fails, but an exception will be thrown if the operator new application fails.

delete first destructs to clean up the resources, and then calls operator delete to release the stack space itself.

In a 32-bit system to apply for a space of 0x7fffffff bytes, the operator new function fails to apply for space and throws an exception:

void f()
{
    void* p3 = malloc(0x7fffffff);
    if (p3 == NULL)
    {
        cout << "malloc fail " << endl;
    }

    void * p4 = operator  new ( 0x7fffffff );
     cout << "Apply for space ing" << endl ;

    char* p5 = new char('C');
    char* p6 = new char[2];

    ListNode* p7 = new ListNode[ 5 ]{ 1 , 2 , 3 , 4 , 5 };
}

int main()
{

    try
    {
        f();
    }
    catch (exception& e)
    {
        cout << e.what() << endl;
    }

    return 0;
}

Failed to apply for space: the application space ing is not printed, indicating that throwing an exception will directly jump to the catch position, and will not execute cout << “Apply for space ing” << endl;

F10 – Debugging – Disassembly, for built-in types, it is found that new calls operator new, and new type [] actually calls operator new[]:

malloc/free and new/delete summary:

Common point: All of them apply for space from the heap and need to be released manually by the user.

the difference:

(1) malloc and free are functions, new and delete are operators

(2) The space applied by malloc will not be initialized, and new can be initialized

(3) When malloc applies for space, you need to manually calculate the size of the space and pass it, new only needs to be followed by the type of space

(4) The return value of malloc is void*, which must be cast when used, and new is not required, because new is followed by the type of space

(5) When malloc fails to apply for space, it returns NULL, so it must be empty when using it, new does not need it, but new needs to catch exceptions

(6) When applying for a custom type object, malloc/free will only open up space, and will not call the constructor and destructor, while new will call the constructor to complete the initialization of the object after applying for the space, and delete will call before releasing the space. The destructor completes the cleanup of resources in the space.

5. Memory leaks

Definition: A memory leak is a situation in which a program fails to free memory that is no longer in use due to an oversight or error. Memory leaks do not refer to the physical disappearance of memory, but that after an application allocates a certain segment of memory, it loses control of the segment of memory due to a design error, resulting in a waste of memory.

Harm: Memory leaks occur in long-running programs, such as operating systems, background services, etc., and memory leaks will cause slower and slower responses and eventually freeze.

If you apply for heap memory, but forget to release it, it will cause a memory leak, but only the pointer is lost, not the memory loss:

int main()
{
    int *p1 = (int *)malloc(sizeof(int));

    return 0;
}

Why won’t the memory be lost?

Because after applying for a space on the heap, you get a pointer to this space, and you can now access this space. But after the access, due to negligence or programming error, there is no such pointer, or this pointer is not used, but I do not know that the pointer has not been released. And memory always exists. Allocating the space to the user means that the right to use this space is handed over to the user. Free means returning this memory space to the operating system, and now the system can re-allocate this space. To other users, so if the memory is not returned, the memory will become less and less until it can no longer be used normally.

Even if the memory leaks in an ordinary program, it is not a big problem, because the program runs a process, each process has its own running space, and they map physical addresses together. As long as the process ends normally, even if there is a memory leak, it will eventually be released. .

You may also like...

Leave a Reply

Your email address will not be published.