[C/C++] C/C++ memory management you can't miss!

1. C/C++ memory distribution

  • First look at a piece of code:
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";
 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);
}

Corresponding location in memory:
Insert picture description here

  • Stack: Store function parameters, local variables, and register information (function ends, stack frame is released), and the stack grows downward
    • The default stack space size under Linux: 8192kb=8M
    • Windows stack space: 1024kb=1M
  • Heap: dynamic memory application, malloc, calloc, realloc, must be released with free, the heap grows upward
  • Data segment: global variables, data modified by static (the life cycle is consistent with the program, the program exits the data is cleared)
  • Code snippet: code and read-only constants

Why divide the memory into different areas?
The data type is different, the data management method is also different, in order to facilitate the search to divide different areas

Two, memory management

2.1 C language memory management:

malloc、calloc、realloc

int* p1 = (int*)malloc(sizeof(int));		// 动态申请int空间大小,随机值
int* p2 = (int*)calloc(4, sizeof(int));		// 动态申请int空间大小,并赋值4
int* p3 = (int*)realloc(p2, sizeof(int) * 10);	//调整p2的空间大小为10个int大小

Same point:

  1. The return value is void*, must be forced to transfer when receiving
  2. The application fails to return NULL, so it must be empty before use

difference:

  1. malloc(size): just apply for the memory of size size
  2. calloc(num, size): The size of the application space is size, and the value is assigned to data
  3. realloc(void* p, size): Adjust the size of the space pointed to by p to size (enlarge or shrink). If p is NULL, the function is similar to malloc. If the size of the space behind p is less than size, find a new space that is enough size, copy the contents of the old space, and finally release the size of the old space.

Note: The memory space requested by malloc will be a bit larger than expected. In the object model, there is 32 bytes of attribute information (including the size of the requested memory, etc.), and the end position of 4 bytes is behind to prevent out of bounds.

2.2 C++ memory management:

Why does C++ create a new memory management method?
C++ is an object-oriented programming. It uses malloc, calloc, and realloc to dynamically open up the size of the class space. It does not call the constructor, so it cannot be called an object. When free is called, the destructor will not be called to clean up the internal resources of the object. May cause memory leaks

  1. Request/release a single type space: new/delete
  2. Apply/release continuous type space: new[]/delete[]

Dynamic application for built-in types:

int* p1=new int(10);10初始化
int* p2=new int[10]{
    
    1,2,3,4,5,6,7,8,9,0}; 申请连续空间并初始化
delete p1;
delete[] p2;

Dynamic application for custom types:

class Test
{
    
    
public:
    Test(int p = 0)
        :p_(p)
    {
    
    
        cout << "构造:" << this << endl;
    }
    ~Test()
    {
    
    
        cout << "析构:" << this << endl;
    }
private:
    int p_;
};

int main()
{
    
    
    Test* p1 = new Test(100);				//会调用构造函数(类内成员t被初始化成1),因此生成的为对象
    Test* p2 = (Test*)malloc(sizeof(Test));	//不会调用(类内成员t没有初始化),因此只能称为和类类型大小相同的堆空间
    delete p1;								//会调用析构函数,清理
    free(p2);								//只会释放开辟的空间
    return 0;
}

The difference between malloc and new:

  1. new is a keyword in C++, malloc is a library function, so the header file must be introduced before use
  2. malloc application/release of space will not call the constructor/destructor, new will call the constructor/destructor
  3. The malloc application fails and returns NULL. Due to the internal implementation of new, there is no return of a null pointer.
  4. The return value of malloc is void*, and new returns a pointer of the corresponding type, so there is no need to force transfer to receive

Note:
new/delete, new[]/delete[], malloc\free must be matched, otherwise it will cause program crash or memory leak

class Test
{
    
    
public:
    Test(int val = 0)
        :p_(new int(val))
    {
    
    
        cout << "构造:" << this << endl;
    }
    ~Test()
    {
    
    
        delete p_;
        cout << "析构:" << this << endl;
    }
private:
    int* p_;
};

int main()
{
    
    
    Test* p1 = (Test*)malloc(sizeof(Test));
    Test* p2 = new Test;
    Test* p3 = new Test[2];
    
    delete p1;      // 程序崩溃,malloc没有调用构造函数
    delete[] p1;    // 程序崩溃,malloc没有调用构造函数

    free(p2);       // 内存泄漏,free没有调用析构函数

    free(p3);       // 程序崩溃,连续空间只释放了一部分
    delete p3;      // 程序崩溃,连续空间只释放了一部分
    return 0;
}

Three, new/delete workflow

3.1 new

  • 1. Apply for heap space
    • Call the void* operator new(size) function to apply for space, size is the space size of the class, and call malloc internally to apply for space
      • Success: return to the first address of the space
      • Failure: call the _callnewh(size) function, call the solution provided by the user, if it fails, throw a bad_alloc type exception, continue to apply for space
  • 2. Call the constructor to initialize the requested space

Summary: Due to the way the operator new() function is executed, new will not return null

3.2 delete

  • 1. Call the destructor to clean up the resources in the object
  • 2. Call operator delete() function, internally call free to release space

3.3 new[]

  • 1. To apply for space, call void* operator new[] (size), and internally call the operator new() function to apply for N class spaces
  • 2. Call the constructor N times to initialize N objects

3.4 delete[]

  • 1. Call the destructor N times to clean up the space resources pointed to by p
  • 2. Call void operator delete[] (void* p) to release the space pointed to by p—>the ​​operator delete function is called internally

Fourth, convert the class space opened up by malloc into objects

  • The space requested by malloc cannot be called an object, because the constructor is not called
  • Position the new expression: call the constructor in the opened heap space, initialize the class space, and make it an object
#include<iostream>
using namespace std;
class Test
{
    
    
public:
	Test(int t = 0)
		:_t(t), _p(new int)
	{
    
    
		cout << "Test(int):" << endl;
	}
	~Test()
	{
    
    
		delete _p;
		cout << "~Test():" << this << endl;
	}
private:
	int _t;
	int* _p;
};
int main()
{
    
    
	Test* pt = (Test*)malloc(sizeof(Test));
	new(pt) Test(100);		// 定位new表达式
	pt->~Test();			// 调用析构函数清理资源
	free(pt);				// 调用free释放空间
	return 0;
}

Guess you like

Origin blog.csdn.net/qq_45691748/article/details/110225950