C/C++ memory management

C/C++ memory distribution

In C/C++, it is usually considered that memory is divided intoheap areastack areamemory mapped segmentStatic area (data segment)Constant area (code segment)
insert image description here

  • Global variables and static variables are stored in the static area (data segment).
  • Local variables, formal parameters, etc. exist in the stack area.
  • The space released by dynamic application is in the heap area.
  • Constant character strings and the like exist in the constant area.
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";
//字符数组存在栈区,“abcd”常量字符串在常量区
const char* pChar3 = "abcd";
//pChar3局部变量在栈区,“abcd”常量字符串在常量区
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
//ptr1,ptr2,ptr3都是局部变量在栈区,其指向的空间在堆区
free(ptr1);
free(ptr3);
}

Dynamic memory management in C

  • malloc
    insert image description here
    The parameter is the size (bytes) of the memory space you want to open up, and the return value is void* and cast as needed.
    The allocated space is not initialized.
  • calloc
    insert image description here
    The function of the two parameters is to open up several spaces required for each (bytes).
    The opened space is initialized to 0.
    For example:
int* a = (int*)calloc(10,sizeof(int));

realloc
insert image description here
Adjust the space pointed to by ptr, which can be expanded or reduced, but it is generally used for expansion. If the first parameter is a null pointer, then its function is equivalent to malloc
expansion

  • In-place expansion: If there is still a lot of space behind the current space for expansion, then the capacity will be expanded in situ.
  • Remote expansion: If there is not enough space behind the current space for capacity expansion, the system will find a new enough space, copy the data in the original space to the new space, and release the original space.
    free
    insert image description here
    Release the dynamically allocated space in the heap

Thinking questions:
4. What is the difference between malloc/calloc/realloc?

malloc and calloc apply for space from the heap area, and realloc adjusts the size of the original space.
When the first parameter of realloc is NULL, it is equivalent to malloc.
The malloc application space is not initialized, and the calloc application space is initialized.
When realloc is expanding, there are problems of in-place expansion and off-site expansion.

Dynamic Memory Management in C++

The dynamic memory management functions in C can no longer fully meet the needs of C++, so a new dynamic memory management method has emerged in C++: new and delete operators for dynamic memory management.

new delete operation built-in type

  • new
int* p1 = new int;
int* p2 = new int[10];

It can be seen that it is very convenient to use the new operator to apply for dynamic resources. There is no need to force type conversion, and there is no need to calculate the size of the space to be opened. Another point is that there is no need to check whether the opening is successful after the application.
After malloc fails to apply for space, it returns a null pointer, so it needs to be checked after using malloc to apply for resources, and after the new operator fails to open up, it uses the method of throwing an exception, which does not need to be checked.

In addition, new can initialize it while applying for space:

int *p1 = new int(6);
int* p2 = new int[6]{
    
    1,2,3,4,5,6};
  • delete
    delete releases the space created by new, and must be used together, delete corresponds to new delete[ ] corresponds to new [ ], if it is not used together, problems may occur (mentioned later).
int* p1 = new int[6];
delete p1;

This will go wrong.

new delete operation custom type

class A
{
    
    
public:
    A(int a = 0,int b = 0)
        :_a(a)
        ,_b(b)
    {
    
    
        cout << "A()" << endl;
    }
    ~A()
    {
    
    
        cout << "~A()" << endl;
    }
private:
    int _a;
    int _b;
};
int main()
{
    
    
    A* p = (A*)malloc(sizeof(A));
    if (p == NULL)
    {
    
    
        perror("malloc fail\n");
        exit(-1);
    }
    free(p);
    A* ptr = new A;
    delete ptr;
    return 0;
}

insert image description here
It can be seen that malloc and free do not call the constructor and destructor of the custom type.
insert image description here
new and delete call the custom type's constructor and destructor.

So new and delete are born for custom types. There is no difference between built-in types and malloc and free (just the difference in usage), but for custom types, new will call the constructor, and delete will call the destructor function.

The constructor cannot be called explicitly (it can be called with positioning new)
The destructor can be called explicitly
insert image description here
insert image description here

operator new and operator delete functions

new and delete are operators for users to apply 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 layer to apply for space, and delete uses the operator delete global function at the bottom layer to release space .

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
    
    
	// try to allocate size bytes
	void *p;
	while ((p = malloc(size)) == 0)
	if (_callnewh(size) == 0)
	{
    
    
	// report no memory
	// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
	static const std::bad_alloc nomem;
	_RAISE(nomem);
}
	return (p);
}

operator new is a global function that encapsulates malloc. If the application fails, it will not return a null pointer, but throw an exception.

/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
    
    
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}

operator delete is also a global function, which is the encapsulation of free.

Implementation principle of new and delete

  • new
    1, call operator new to apply for space
    2, call the constructor
  • new [ ]
    1. To call the opeartor new[ ] function is to call the operator new function multiple times to apply for multiple spaces.
    2. To call the constructor multiple times
  • delete
    1. Call the destructor on the requested space to clean up the object.
    2. Call the operator delete function to release the requested space
  • delete[ ]
    1. Call the destructor multiple times on the requested space to clean up the object.
    2. To call operator delete [ ] is to call the operator delete function to release space.

Why do you say that new delete new[] delete[] malloc free should be used together, the following example is enough to prove:
Tell me, how are new[ ], and delete[ ] implemented?

int* p1 = new int[6];

[6] will tell the compiler to apply for 6 int-sized spaces and complete 6 constructor calls.

delete[] p1;

delete[ ] does not specify how to release the space of several objects and call the destructor several times. How does it do it?
In fact, when new [ ] is used, the compiler will do some small operations to allow it to open up 4 more bytes of space to store and open up space for several objects for use by delete [ ].
insert image description here
If you use delete or free to release this space at this time, an error will be reported, because it is not allowed to release the dynamically opened space from the middle part. And because the destructor will only be called once, the cleanup cannot be done for all objects.

class A
{
    
    
public:
    A(int a = 0,int b = 0)
        :_a(a)
        ,_b(b)
    {
    
    
        cout << "A()" << endl;
    }
    ~A()
    {
    
    
        cout << "~A()" << endl;
    }
private:
    int _a;
    int _b;
};
int main()
{
    
    
    A* ptr1 = new A[6];
    delete ptr1;
    return 0;
}

insert image description here

Locating the use of new

As mentioned above, when malloc operates a custom type, the constructor will not be called, and the method of locating new can display the call to the constructor.

class A
{
    
    
public:
    A(int a = 0,int b = 0)
        :_a(a)
        ,_b(b)
    {
    
    
        cout << "A()" << endl;
    }
    ~A()
    {
    
    
        cout << "~A()" << endl;
    }
private:
    int _a;
    int _b;
};
int main()
{
    
    
    A* ptr = (A*)operator new(sizeof(A));
    new(ptr)A(2, 3);
    return 0;
}

insert image description here
After locating new
insert image description here
This is just for example, locating new is usually used with the memory pool.Because the memory allocated by the memory pool is not initialized, if it is an object of a custom type, it needs to use the definition expression of new to explicitly call the constructor for initialization.

Guess you like

Origin blog.csdn.net/Djsnxbjans/article/details/129538892