[C++] Dynamic memory management (I can’t understand the article written in 79 minutes, come and learn)

Dynamic memory management directory:

1. C/C++ memory distribution

 After learning the division of C/C++ memory areas, let’s do a few questions to consolidate:

1. Multiple choice question: Options: A. Stack B. Heap C. Data segment (static area) D. Code segment (constant area) Where is globalVar? ____ Where is staticGlobalVar? Where is ____staticVar? ____ Where is localVar? Where is ____num1? ____Where is char2? ____ Where is *char2? ___Where is pChar3? ____ Where is *pChar3? Where is ____ptr1? ____ Where is *ptr1? ____

2. Fill in the blanks: sizeof(num1) = ____; sizeof(char2) = ____; strlen(char2) = ____; sizeof(pChar3) = ____; strlen(pChar3) = ____; sizeof(ptr1) = ____;

2. C language dynamic memory management method

malloc:

calloc:

realloc:

free:

 Interview question: What is the difference between malloc/calloc/realloc?

3. C++ dynamic memory management method (operator new/delete+construction/destruction)

3.1new/delete operation built-in types

3.2new/delete operation custom type

4. operator new and operator delete (explore the bottom layer of new operator)

5. Position new expression (understand)

6. Common interview questions

1. The difference between malloc/free and new/delete (understand from the usage function and bottom layer)

2. Memory leak (not space lost)

What is a memory leak

The dangers of memory leaks

How to avoid memory leaks


1. C/C++ memory distribution

In the C language stage, we often say that local variables are stored in the stack area, data in dynamic memory is stored in the heap area, static variables are stored in the static area, and constants and global variables are stored in the constant area. In fact, what we call here are the stack area, The heap area, static area and constant area are all  part of the virtual process address space  . The specific memory areas are divided as follows:

This picture is highly recommended, gnaw gnaw gnaw gnaw gnaw gnaw   

  •  Stack: Also called stack, it is used to store non-static local variables, function parameters, function return values, etc. The stack grows downward (the stack frame is like a disposable water cup)
  • Heap: used for dynamic memory allocation when the program is running. The heap grows upward.
  • Data segment (static area): Usually called the data segment in Linux, it is used to store global data and static data (the static area does not just have static variables)
  • Code segment (constant area): usually called code segment in Linux, used to store executable code instructions and read-only constants

 After learning the division of C/C++ memory areas, let’s do a few questions to consolidate:

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
	static int staticVar = 1;
	int localVar = 1;
	int num1[10] = { 1, 2, 3, 4 };
	char char2[] = "abcd";
	const char* pChar3 = "abcd";
	int* ptr1 = (int*)malloc(sizeof(int) * 4);
	int* ptr2 = (int*)calloc(4, sizeof(int));
	int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
	free(ptr1);
	free(ptr3);
}

1. Multiple choice question:
Options: A. Stack B. Heap C. Data segment (static area) D. Code segment (constant area)
Where is globalVar? ____ Where is staticGlobalVar? ____
Where is staticVar? ____ Where is localVar? ____
Where is num1? ____
Where is char2? ____ Where is *char2? ___
Where is pChar3? ____ Where is *pChar3? ____
Where is ptr1? ____ Where is *ptr1? ____

Analysis: The upper half of the area is relatively simple. Those with static and global in front are all in the static area, and those opened in functions without static are all on the stack.

The lower half is the difficult part. Please take a good look at the picture I drew below:

It can be seen that since char2 pChar3 ptr1 are all in Test, their address space is opened in the stack frame, but where their contents are depends on the type and development method: for char2, it is just ordinary development, so the object is also On the stack; for pChar3 , there is const before the type, which is a pointer pointing to "abcd" of the code segment, so *pchar3 is in the code segment; for *ptr1 , the opening method is to open in the heap area, so *ptr1 The data is in the heap area

2. Fill in the blanks:
sizeof(num1) = ____;
sizeof(char2) = ____; strlen(char2) = ____;
sizeof(pChar3) = ____; strlen(pChar3) = ____;
sizeof(ptr1) = ____;

sizeof is an operator/keyword. It can be followed without parentheses and directly followed by the type.

In addition, sizeof calculates the number of bytes of space occupied by the variable ;

And strlen is a function, it must be called with parentheses, and strlen counts the number of characters in the string (excluding '\0')

 For the sizeof pointer, the pointer is the address, so the sizes of 32-bit and 64-bit are different, so it is 4/8


2. C language dynamic memory management method

In C language we use malloc/calloc/realloc/free functions for dynamic memory management:

malloc:

int* p1 = (int*)malloc(sizeof(int));
	if (p1 == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

 The reason for checking null here is because the compiler is not rigorous, so judgment must be added. Moreover, when the development fails, malloc returns a null pointer, so it can be checked like this

calloc:

int* p2 = (int*)calloc(4, sizeof(int));
	if (p2 == NULL)
	{
		perror("calloc fail");
		exit(-1);
	}

realloc:

int* p3 = (int*)realloc(p2, sizeof(int) * 10);
	if (p3 == NULL)
	{
		perror("realloc fail");
		exit(-1);
	}

free:

 

free(p1);
free(p3);

 Interview question: What is the difference between malloc/calloc/realloc?

  • malloc is used to open up a piece of dynamic memory. When using it, you need to specify the size of the opened space (bytes). If the opening is successful, it will return the starting address of the space. If the opening fails, it will return NULL and will not be initialized (so new appears)
  • The usage of calloc is similar to malloc, except that it has two parameters, the first parameter is the number of elements, the second parameter is the size of each element, and it will initialize all the data in the space to 0 ;
  • realloc is used to expand/contract space. It has two parameters. The first parameter is the starting address of the dynamic memory that needs to be adjusted. The second parameter is the adjusted space size. If the first parameter is NULL, Then it is equivalent to malloc; if it is expanded, the compiler will check whether there is enough space after the original space. If it is enough, it will directly expand and return the starting address of the original space. If it is not enough, it will open up a new space and then move the original space. The data of the space is copied to the new space and the address of the new space is returned, and finally the original space is released; if the capacity is reduced, the compiler will directly open up a new space, then copy the data of the original space to the new space and return the address of the new space, and then release it. original space.

3. C++ dynamic memory management method (operator new/delete+construction/destruction)

C++ is compatible with the C language, so the memory management method of the C language can continue to be used in C++. However, because it is more troublesome to use and cannot be used in some places, C++ has proposed its own memory management method: through the new and delete operators . Dynamic memory management

3.1new/delete operation built-in types

If you are applying for built-in type space, new and malloc, delete and free are basically similar. The difference is: new/delete applies for and releases the space of a single element, while new[] and delete[] apply for continuous space. , and new will throw an exception when it fails to apply for space, and malloc will return NULL if it fails to apply for space.

If you forget what built-in types are, look at starting with constructors

For built-in types , there is no obvious difference between the memory management methods of C language and C++ , except that in C++, the new operator is used to replace the malloc/calloc function in C language, and the delete operator is used to replace the free function;

At the same time, since new and delete are operators/keywords rather than functions, they do not need to be followed by parentheses, but can be directly followed by the type; in addition, new can be initialized while opening up space (on the basis of the constructor superior)

Note: C++ does not support expansion. To expand, you have to open up new space, copy data, and then destroy the original space.

void Test()
{
	//申请单个空间不初始化
	int* p1 = new int;

	//申请单个空间并初始化
	int* p2 = new int(10);

	//申请连续空间不初始化
	int* p3 = new int[10];

	//申请连续空间并初始化
	int* p4 = new int[10]{ 1,2,3,4,5 };

	//释放单个空间
	delete p1;
	delete p2;

	//释放多个空间
	delete[] p3;
	delete[] p4;
}

So there are still differences between managed objects and managed object arrays:

 

 To apply for and release space for a single element, use the new and delete operators. To apply for and release continuous space, use new[] and delete[]. Note that the two must be used in a matching manner, that is, delete cannot be used to release the space opened by new[]. space

3.2new/delete operation custom type

The principle of new:

  1. Call the operator new function to apply for space;
  2. Call the constructor on the applied space to complete the initialization of the object;

The principle of delete:

  1. Execute the destructor on the space to complete the cleanup of resources in the object;
  2. Call the operator delete function to release the object's space;

The principle of new T[N]:

  1. Call the operator new[] function, and actually call the operator new function in operator new[] to complete the application for N object spaces;
  2. Call the constructor N times on the requested space;

The principle of delete[]:

  • Execute N destructors on the released object space to complete the cleanup of resources in N objects;
  • Call operator delete[] to release space, and actually call operator delete in operator delete[] to release space;

The biggest difference between C++ dynamic memory management and C language dynamic memory management is how they handle custom types: C language malloc/calloc/realloc functions are only responsible for opening up space, and free functions are only responsible for destroying space; while C++ is applying for custom types When there is space, new will call the constructor and delete will call the destructor.


class A
{
public:
A (int a=0 ):_a(a)
{
	cout << "A Construct" << this << endl;
}
~A()
{
	cout << "~A()"<< this << endl;
}
private:
int _a;
};


4. operator new and operator delete (explore the bottom layer of new operator)

In C++, new and delete are operators used by users to apply for and release dynamic memory . Operator new and operator delete are global functions provided by the system . New calls the operator new global function at the bottom to apply for space, and delete uses the operator delete global function at the bottom. function to free up space . (So ​​there is a calling relationship between them, not an overloading relationship)

It is important to note that the operator new and operator delete functions are not operator overloading , because their parameters do not have custom types, but are global functions implemented in the library. They are just named operator. Many C++ beginners will I was misled by the function names of the two.

The underlying operator new and operator delete functions in C++ are as follows:

 

We can verify the underlying calls to new and delete by looking at the disassembly code:

 As for new[] and delete[], they realize their functions by calling operator new[] and operator delete[] functions, but in fact, operator new[] and operator delete[] are also called operator new and operator delete at the bottom. function:

 Through the above experiments, we know that operator new actually applies for space through malloc . If malloc applies for space successfully, it will return directly. Otherwise, the user-provided response to insufficient space will be implemented. If the user provides the measure, it will continue to apply, otherwise an exception will be thrown . operator delete finally releases space through free 

Therefore, new actually encapsulates malloc. Failure to apply for memory will result in bad allocation. This is more in line with the C++ object-oriented problem-solving mechanism.


5. Position new expression (understand)

Positioning new is also called replacement new. The positioning new expression is to call the constructor to initialize an object in the allocated original memory space ; its usage format is as follows:

new(place_address) type 或者 new (place_address) type(initializer-list)

 scenes to be used

In practice, the positioning new expression is generally used in conjunction with the memory pool  - because the memory allocated by the memory pool is not initialized, so if it is a custom type object, you need to use the definition expression of new to explicitly call the constructor for initialization; and the memory We will study the pool in detail later, so let’s take a look at it here.

Briefly understand the memory pool:

Suppose there is a village halfway up the mountain. However, due to various reasons, there is no drinking water in the village. So every time people drink water, they can only queue up at the public well at the foot of the mountain to get water. However, the queue is very slow, so the village chief uses a water pump + The water pipe is connected to the well and a reservoir has been built at home. In the future, if you need water, you can go directly to the reservoir instead of queuing up the mountain to fetch water, which greatly improves efficiency.

In the above example, the water well shared by the whole village is equivalent to the heap. The other villagers queuing up to fetch water are equivalent to the malloc/calloc/realloc function applying for space in the heap area. The water reservoir in the village chief's house is equivalent to our protagonist - the memory pool. , the establishment of a memory pool can make our application for space very efficient.


6. Common interview questions

1. The difference between malloc/free and new/delete (understand from the usage function and bottom layer)

What malloc/free and new/delete have in common is that they both apply for space from the heap and require the user to release it manually; the differences are:

  • malloc and free are functions , new and delete are operators ;
  • When applying for built-in type space, the space applied for by malloc cannot be initialized, but new can be initialized (for custom types)
  • When applying for a custom type object, malloc/free will only open up space and will not call the constructor and destructor. New will call the constructor to complete the initialization of the object after applying for space, and delete will call the destructor before releasing the space. Complete the cleanup of resources in the space;
  • When malloc applies for space, you need to manually calculate the space size and pass it . New only needs to be followed by the type of space. If there are multiple objects, just specify the number of objects in [];
  • The return value of malloc is void* , which must be forced when used . New does not need to, because new is followed by the type of space ;
  • When malloc fails to apply for space, it returns NULL, so it must be null when used . New does not need to, but new needs to catch exceptions ;

2. Memory leak (not space lost)

What is a memory leak

In layman's terms: It's just occupying Bryce. Although I don't use this space, I just don't release it. It's because the pointer is lost and can't be found, not that the memory is lost.

Definition: A memory leak refers to a situation where the program fails to release memory that is no longer used due to negligence or error; a memory leak does not refer to the physical disappearance of memory, but to the loss of memory due to design errors after the application allocates a certain segment of memory. Loss of control over this segment of memory, thus causing a waste of memory

The dangers of memory leaks

In small programs and small codes, the harm of memory leaks is almost zero. However, for large companies, such as King of Glory, when a memory leak occurs and is chronic and difficult to detect, the space is always occupied and cannot be reclaimed. This is Will cause problems such as server hang up

Definition: Memory leaks in short-running programs are not harmful, because all dynamically applied space will be reclaimed when the program ends; memory leaks in long-running programs have a great impact, such as operating systems, background services, etc., when memory leaks occur Leaks will cause the response to become slower and slower, and eventually freeze.

How to avoid memory leaks

  1. Develop good design standards in the early stage of the project, develop good coding standards, and remember to release the memory space that matches the application; (Note: This is an ideal state, but if you encounter an abnormality, even if you pay attention to the release, it may still occur. Problem, it needs to be managed by the next smart pointer to ensure it)
  2. Use RAII ideas or smart pointers to manage resources;
  3. Some companies use internally implemented private memory management libraries for internal specifications; this library comes with memory leak detection function options;
  4. Use memory leak tools to detect when something goes wrong. (Note: Many tools are unreliable or expensive)

Summary: Memory leaks are very common, and the solutions are divided into two types:

 1. Preventive type; such as smart pointers , etc. 2. Post-event error checking type; such as leak detection tools


I hope this article can bring you results! !

Guess you like

Origin blog.csdn.net/weixin_62985813/article/details/132916223