[C++ dry goods store] Memory management new and delete

================================================ ==========================

Click to go directly to the personal homepage: Xiaobai is not a program Yuan

C++ Series Column: C++ Dry Goods Shop

Code repository: Gitee

================================================ ==========================

Table of Contents

Dynamic memory management in C language

What is the difference between malloc/calloc/realloc?

C++ memory management methods

built-in types

Custom type

operator new and operator delete functions

operator new

operator delete

Implementation principles of new and delete

built-in types

The principle of new

The principle of delete

The principle of new T[N]

The principle of delete[]

Positioning new expression (placement-new)

The difference between malloc/free and new/delete

memory leak

What is a memory leak and the dangers of memory leaks

Memory leak classification

How to avoid memory leaks


Dynamic memory management method in C language

Memory allocation function:

malloc/cealloc/realloc

Memory destruction function:

free

int main()
{
//malloc
int* ptr = (int*)malloc(sizeof(int) * 10);
free(ptr);
//calloc
int* ptr2 = (int*)calloc(4, sizeof(int));
//realloc
int* ptr3 = (int*)realloc(ptr2, sizeof(int) );
free(ptr3);
return 0;
}

The difference between malloc/calloc/realloc?

malloc

void* malloc (size_t size);

Allocates a block of memory of size bytes, returning a pointer to the beginning of the block. The contents of the newly allocated memory block are not initialized but retain undefined values. If size is zero, the return value depends on the specific library implementation (it may or may not be a null pointer), but the returned pointer should not be dereferenced.

calloc

void* calloc (size_t num, size_t size);

Allocate a block of memory for an array of num elements, each of which is bytes long, and initialize itsall bits to zero. The effective result is to allocate a zero-initialized block of (num*size) byte memory. If size is zero, the return value depends on the specific library implementation (it may or may not be a null pointer), but the returned pointer should not be dereferenced.

realloc

void* realloc (void* ptr, size_t size);

Change the size of the memory block pointed to by ptr. Even if a memory block is moved to a new location, the contents of the memory block are retained to the smaller of the old and new sizes. If the new size is larger, the value of the newly allocated portion is undefined. If ptr is a null pointer, this function behaves like malloc, allocating a new block of bytes of size and returning a pointer to its beginning.

More C language dynamic memory functions move here:

Dynamic memory management_Xiaobai is not Program Yuan’s blog-CSDN blogicon-default.png?t=N7T8https://blog.csdn.net/qq_55119554/article/details/131737338

C++ memory management method

The C language memory management method can continue to be used in C++, but it cannot be used in some places, and it is more troublesome to use, so
This C++ also proposes its own memory management method: dynamic memory management through new and deleteoperators.

built-in type

//Built-in type

int main()
{
//Dynamicly apply for a space of type int
int* p = new int;
//Destroy dynamically applied space
delete p;
//Dynamicly apply for a space of type int and initialize it to 0
int* p2 = new int(0);
delete p2;
//Dynamicly apply for 10 int type spaces
int* p3 = new int[10];
delete p3;
//Dynamicly apply for 10 int type spaces and initialize the first three elements to 1, 2, 3 and the rest to 0
int* p4 = new int[10] { 1,2,3 };
delete p4;
return 0;
}

Note:

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: Match them together.

custom type

//Custom type

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

int main()
{

A* ptr = new A;
delete ptr;
A* ptr2 = new A(0);
delete ptr2;
A* ptr3 = new A[5];
delete[10] ptr3;
A* ptr4 = new A[5]{ 1,2,3 };
delete[5] ptr4;

return 0;
}

This is the biggest role of new in C++ that is different from malloc in C language: defining a class and being able to initialize it.

Note:

When applying for a custom type space, new will call the constructor, delete will call the destructor, and malloc and
free will not.

operator new and operator delete functions

new and delete are the operators used by users to dynamically memory application and release. Operator new and operator delete are
Global function provided by the system, new calls operator new global function at the bottom to apply for space, delete passes at the bottom
operator delete global function to free up space.

operator new

operator new: This function actually applies for space through malloc, and returns directly when malloc successfully applies for space; apply for space
If it fails, try to implement insufficient space countermeasures. If the countermeasures are set by the user, continue to apply, otherwise an exception will be thrown.

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
    // If the application for memory fails, a bad_alloc type exception will be thrown here.
    static const std::bad_alloc nomem;
    _RAISE(nomem);
  }
return(p);
}

operator delete

operator delete: This function finally releases space through 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;
}
/*
implementation of free
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

Through the implementation of the above two global functions, we know that operator new actually uses malloc to apply for space. If
If malloc successfully applies for space, it will return directly. Otherwise, the user-provided response to insufficient space will be executed. If the user provides this measure
Just continue to apply, otherwise an exception will be thrown. operator delete ultimately releases space through free.

The implementation principle of new and delete

Built-in types

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

Principle of new

1. Call the operator new function to apply for space
2. Execute the constructor on the requested space to complete the construction of the object

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

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. Execute the constructor N times on the requested space

Principle of delete[]

1. Execute N destructors on the released object space to complete the cleanup of resources in N objects.
2. Call operator delete[] to release space. Actually, operator delete is called in operator delete[] to free up space.
Make space

Let’s try running the above code

Positioning new expression (placement-new)

Concept:

The positioned new expression is to call the constructor to initialize an object in the allocated original memory space.

Use format:

new (place_address) type or new (place_address) type (initializer-list)
place_address must be a pointer, initializer-list is the initialization list of the type

Positioning new expressions are generally used in conjunction with memory pools in practice. Because the memory allocated by the memory pool is not initialized, if
If it is an object of a custom type, you need to use the definition expression of new to explicitly call the constructor for initialization.

Usage scenarios:

class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" <<this << endl;
}
~A()
{
cout << "~A():" <<this << endl;
}
private:
int _a;
};
// Position new/replacement new
int main()
{
// p1 now points to a space of the same size as the A object. It cannot be regarded as an object because the constructor does not
There is execution
A* p1 = (A*)malloc(sizeof(A));
new(p1)A; // Note: If the constructor of class A has parameters, parameters need to be passed here
p1->~A();
free(p1);
A* p2 = (A*)operator new(sizeof(A));
new(p2)A(10);
p2->~A();
operator delete(p2);
return 0;
}

The difference between malloc/free and new/delete

Common points:

They all apply for space from the heap and require the user to release it manually.

Differences:

  • malloc and free are functions, new and delete are operators
  • The space requested by mallocwill not be initialized, but new caninitialize
  • 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, specify the number of objects in [].
  • The return value of malloc is void*, which must be forced when used. Newis not required because new is followed by the type of space.
  • When mallocfails to apply for space, itreturns NULL, so it must benull when used, and newis not required. But newneeds to catch exceptions
  • 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 space< /strong>, delete will call the destructor to complete the cleanup of resources in the space before releasing the space

Memory leak

What is a memory leak and the dangers of a memory leak

What is a memory leak:

A memory leak occurs when a program fails to release memory that is no longer in use due to negligence or error. Memory leaks do not mean the physical disappearance of memory, but that after the application allocates a certain segment of memory, it loses control of the memory segment due to design errors, thus causing a waste of memory.

The dangers of memory leaks:

Memory leaks in long-running programs, such as operating systems, background services, etc., have a great impact. Memory leaks will cause the response to become slower and slower, and eventually freeze.

Memory Leak Classification

In C/C++ programs, we generally care about two aspects of memory leaks:

Heap leak

Heap memory refers to a piece of memory allocated from the heap through malloc / calloc / realloc / new, etc. according to needs during program execution. After use, it must be deleted by calling the corresponding free or delete. If a design error in the program results in this part of the memory not being released, then this part of the space will no longer be able to be used, and a Heap Leak will occur.

System resource leak

It means that the program uses resources allocated by the system, such as sockets, file descriptors, pipes, etc., without using corresponding functions to release them, resulting in a waste of system resources, which can seriously lead to reduced system performance and unstable system execution.

How to avoid memory leaks

1. Establish 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. ps:
this ideal state. But if you encounter an exception, even if you pay attention to the release, problems may still occur. Need next piece of wisdom
It is guaranteed to be managed by pointers.
2. Use RAII ideas or smart pointers to manage resources.
3. Some companies’ internal specifications use internally implemented private memory management libraries. This library comes with built-in memory leak detection options.
4. If something goes wrong, use the memory leak tool to detect it. ps: However, many tools are unreliable or expensive.

To summarize:
Memory leaks are very common and there are two solutions:

1. Preventive type. Such as smart pointers, etc. (Smart pointers, will be discussed later)

2. Check for errors afterwards. Such as leak detection tools.

Today’s sharing ends here! If you think the article is good, you can support it three times in a row. Your support is the driving force for me to move forward!

syntaxbug.com © 2021 All Rights Reserved.