Table of contents
Two, C language memory management method
3. C++ memory management method
3.4 new/delete operation built-in type
1. Use new to allocate memory:
3.5 new and delete operation custom type
Fourth, the realization principle of new and delete
4.1. operator new 和 operator delete:
4.2 operator new[] 和 operator delete[]:
2. The class type processing of delete:
introduction
In the field of computer programming, memory management is a critical task, especially in low-level programming languages such as C and C++. Good memory management practices can ensure program performance and stability. This article will explore various aspects of C/C++ memory management in depth, and help readers better understand how to correctly allocate and release memory, and improve programs through optimization strategies.
1. Stack and heap memory
1.1 Stack memory
Stack memory is an area stored in computer memory that manages local variables and function calls . Stack memory works as follows:
-
Automatic management : The allocation and release of stack memory is automatically handled by the compiler. When entering a function, the compiler allocates memory for its local variables on the stack, and when the function exits, the memory occupied by these local variables is automatically released. This automatic management mechanism ensures that the lifetime of local variables matches the lifetime of function calls.
-
Fast speed : Since the management of stack memory is automatically done by the compiler, memory allocation and release operations on the stack are very fast. This makes stack memory suitable for temporary, short-lived variables.
-
Limited size : The size of the stack is usually fixed, depending on the operating system and compiler settings. This means that the capacity of stack memory is limited, and too many local variables may lead to stack overflow.
-
Last-in-first-out ( LIFO ) : Stack memory follows the principle of last-in-first-out. That is, the last local variable allocated is the first to be freed.
Stack memory is usually used to store function parameters, local variables, and function call information. It plays an important role in handling function calls and returns
1.2 Heap memory
Heap memory is a memory area dynamically allocated when the program is running to store data structures and objects. Features of heap memory include:
-
Manual management : Unlike the stack, the allocation and release of heap memory needs to be done explicitly by the programmer. In C,
malloc
heap memory is allocated using functions, while in C++, this can benew
achieved using operators. To release the heap memory, you need to use the corresponding function (free
anddelete
) to manually release it to avoid memory leaks . -
Flexible size : There is no fixed limit on the size of the heap memory, allowing dynamic allocation of memory at runtime. This makes heap memory suitable for storing data structures of indeterminate size , such as dynamic arrays and complex objects.
-
Slow speed : Since the allocation and release of heap memory requires the programmer to explicitly operate, the operation speed is relatively slow. Frequent heap memory allocations and deallocations can affect program performance .
-
Beware of memory leaks : Since heap memory needs to be freed manually, memory leaks can occur if a block of memory is not freed properly when it is no longer needed. A memory leak can cause a program to consume more and more memory, which can eventually lead to a crash.
Heap memory is typically used to store data that has a long life cycle, is indeterminate in size, or needs to be allocated dynamically.
1.3 Examples
Let's look at some examples:
C example
C++ example
The difference between the two is only in the way of opening up space and releasing space, but the basic logic is similar! !
Two, C language memory management method
malloc
When it comes to the dynamic memory management functions ( ,calloc
,realloc
andfree
) in C language , it is very important to understand their usage and principle. Below are detailed descriptions of each function, usage examples, and anatomy of the inner workings.
2.1 malloc function
introduce
malloc
The function is used to allocate a memory block of the specified size and returns a pointer to the allocated memory. The initial value in the memory it allocates is undefined , usually garbage . Returns if allocation failsNULL
.
usage example
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
ptr = (int *)malloc(sizeof(int)); // 分配一个 int 大小的内存块
if (ptr != NULL) {
*ptr = 42;
printf("Value: %d\n", *ptr);
free(ptr); // 释放分配的内存
}
return 0;
}
Principle Analysis
malloc
The function allocates a contiguous memory area in the heap memory according to the requested size. It returns a pointer to the start address of the allocated memory region. When calledmalloc
, the system searches for a suitable block of free memory and marks it as taken so that future allocations do not overlap.
2.2 calloc function
introduce
calloc
The function is used to allocate a specified number and size of memory blocks and initialize the allocated memory to zero . It takes two arguments, the number of memory blocks required and the number of bytes in each block , and returns a pointer to the allocated memory. Returns if allocation failsNULL
.
usage example
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
ptr = (int *)calloc(1, sizeof(int)); // 分配一个 int 大小的内存块,初始化为零
if (ptr != NULL) {
printf("Value: %d\n", *ptr);
free(ptr); // 释放分配的内存
}
return 0;
}
Principle Analysis
calloc
The function allocates a contiguous area of memory in heap memory whose size is the number of required memory blocks multiplied by the number of bytes in each block. After the allocation is complete, the system sets all bytes in the allocated memory region to zero .
2.3 realloc function
introduce
realloc
Function used to reallocate the size of the allocated memory. It takes a pointer to the allocated memory and the number of bytes of memory needed, and returns a pointer to the reallocated memory. Returned if reallocation failsNULL
. After callingrealloc
, the original pointer may be freed, so the new pointer returned should be used.
explain
- Function prototype:
void *realloc(void *ptr, size_t size);
- Parameters
ptr
: A pointer to a block of memory previously allocated bymalloc
,calloc
or .realloc
Ifptr
is a null pointer (ieNULL
), thenrealloc
behaves as ifmalloc
.- Parameters
size
: The new size of the memory block to reallocate, in bytes.
effect
- If the pointer passed in
ptr
isNULL
, thenrealloc
will behave likemalloc
, allocate a new memory block, and return a pointer to this memory.size
If a parameter of 0 is passed in ,realloc
the behavior of will vary depending on the implementation, but will usually freeptr
the memory block pointed to by and return a null pointer. This can be used to free allocated memory blocks.- If the passed in
ptr
pointer is notNULL
, andsize
is greater than 0,realloc
an attempt will be made to reallocateptr
the memory block pointed to by to make it sizesize
bytes. This can result in one of the following:
- If the size of the original memory block is large enough to accommodate the new size, the memory block will be reallocated without changing its address, and the
realloc
original pointer will be returned.- If the size of the original memory block is not enough to accommodate the new size,
realloc
it will try to find a large enough block in memory to accommodate the new size of data, and then copy the original data to the newly allocated memory block, the original memory block will be released, andrealloc
return Pointer to newly allocated memory.
It should be noted that realloc
data copying and memory block movement may occur during the process of reallocating memory blocks, so it needs to be used with caution in performance-sensitive scenarios . At the same time, realloc
after using , the original pointer may be invalid , and the returned pointer of should always be used realloc
to access the reallocated memory.
usage example
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr;
ptr = (int *)malloc(sizeof(int)); // 分配一个 int 大小的内存块
if (ptr != NULL) {
*ptr = 42;
ptr = (int *)realloc(ptr, sizeof(int) * 2); // 重新分配为 2 个 int 大小的内存块
if (ptr != NULL) {
printf("Value: %d\n", *ptr);
free(ptr); // 释放分配的内存
}
}
return 0;
}
Principle Analysis
realloc
The function reallocates the size of the allocated memory. The memory block may be shrunk if the new size is smaller than the original size. If the new size is larger than the original size, the system may reallocate a larger memory block next to the original memory block or other suitable location, and copy the data from the original memory block to the new memory block. If the reallocation fails, the original memory block will remain unchanged.
2.4 free function
introduce
free
function is used to free memory previously allocated bymalloc
,calloc
or .realloc
After freeing memory, pointers to that memory become invalid and should no longer be used.
usage example
#include <stdlib.h>
int main() {
int *ptr;
ptr = (int *)malloc(sizeof(int)); // 分配一个 int 大小的内存块
if (ptr != NULL) {
*ptr = 42;
free(ptr); // 释放分配的内存
}
return 0;
}
Principle Analysis
free
The function marks a block of memory previously allocated by the dynamic memory allocation function as free so that it can be reused in future allocations. Freed memory is not immediately returned to the operating system, but is left on the heap for futuremalloc
orcalloc
calls.
In summary, the dynamic memory management functions ( malloc
, calloc
, realloc
and free
) allow more flexible memory usage by allowing memory to be allocated and deallocated at runtime. But make sure to release memory in good time to avoid memory leaks and dangling pointer problems. At the same time, be aware that reallocating memory may cause data duplication, which may affect performance.
2.5 Hanging Pointer
concept
A dangling pointer is a pointer to freed or invalid memory. A pointer becomes a dangling pointer when it points to a memory block that has been freed or to an object that is no longer valid. Accessing dangling pointers may lead to program crashes, undefined behavior, or unpredictable results.
There are two main reasons for dangling pointers:
1. The pointer is not nulled after releasing the allocated memory: After using free
or delete
to release the memory, if the pointer is not set to NULL
, the pointer still maintains the previous address, but the pointed memory is invalid. Such a pointer is a dangling pointer.
int *ptr = (int *)malloc(sizeof(int));
free(ptr); // 内存释放
// 这时 ptr 是一个悬挂指针
2. A function returns a pointer to a local variable: If a function returns a pointer to its local variable and you try to use that pointer after the function returns, you will get a dangling pointer because the lifetime of the local variable ends after the function returns .
int *getLocalPtr() {
int x = 10;
return &x; // 返回局部变量的指针
}
int main() {
int *ptr = getLocalPtr(); // ptr 变成悬挂指针
// 后续对 ptr 的使用将导致未定义行为
return 0;
}
3. C++ memory management method
When it comes to dynamic memory management in C++ programming, "new" and "delete" are two very important keywords. They are used to allocate and free memory while the program is running in order to create and destroy objects on the heap. The following is a detailed explanation of "new" and "delete":
3.1 new operator
"new" is the operator used in C++ to dynamically allocate memory on the heap. Its basic syntax is as follows:
where T
is the data type of the memory to be allocated and pointer
is a pointer to the allocated memory. The "new" operator performs the following steps:
- Allocates memory of sufficient size to store
T
objects of type . - Call
T
the type's constructor to initialize the new object. - Returns a pointer to the new object.
example
3.2 delete operator
"delete" is the operator used to free memory allocated by "new". Its syntax is as follows:
where pointer
is a pointer allocated via "new". The "delete" operator performs the following steps:
- Call the pointed-to object's destructor to clean up resources.
- Frees the memory occupied by the object.
- Invalidates a pointer to avoid accesses to freed memory.
example
3.3 Precautions
- Each "new" call must be freed with a corresponding "delete" operation to avoid memory leaks.
- Do not try to call "delete" multiple times on the same pointer, this may result in undefined behavior.
- To avoid dangling pointers, set the pointer to nullptr after freeing the memory.
C++11 introduces replacements for "new" and "delete": "new[]" and "delete[]" , which are used to allocate and deallocate arrays. For example:
std::unique_ptr
However, a better practice is to use smart pointers (eg , ) in modern C++ std::shared_ptr
to reduce the complexity and risk of manual memory management. These smart pointers can automatically free memory when they go out of scope.
3.4 new/delete operation built-in type
The "new" and "delete" operators work similarly to custom types when dealing with built-in types (such as integers, floats, etc.). Here's an example of how to use the "new" and "delete" operators with built-in types:
1. Use new to allocate memory:
2. Use delete to release memory:
It should be noted that the memory allocated by the "new" operator needs to be released by the corresponding "delete" operator to avoid memory leaks. Also, if you forget to call "delete" after allocating memory, you will cause a memory leak.
However, when dealing with built-in types, it is generally preferable to use automatic storage on the stack, which means that the variable is automatically deallocated when the scope in which it resides ends. This avoids the complexity and risks of manual memory management. For example:
3.5 new and delete operation custom type
In C++, you can use the "new" and "delete" operators to dynamically allocate and free memory of user-defined types, ie user-defined class objects. Here is an example of how to use the "new" and "delete" operators when dealing with custom types:
class Person {
public:
Person(const std::string& name, int age) : name(name), age(age) {}
void DisplayInfo() const {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
private:
std::string name;
int age;
};
1. Use new to allocate a custom type object:
2. Use delete to release the custom type object:
Note the following two points:
- The "new" operator calls the class's constructor to initialize the object.
- The "delete" operator calls the class's destructor to clean up resources and free memory.
However, for better memory management, modern C++ recommends using smart pointers instead of explicit "new" and "delete" operations. Here's std::unique_ptr
an example of using to handle custom type objects:
#include <memory>
// ...
std::unique_ptr<Person> personPtr = std::make_unique<Person>("Bob", 30);
// 使用 unique_ptr 分配一个 Person 对象
In this case, personPtr
the associated memory is automatically freed when the goes out of scope, no need to call "delete" manually.
If multiple smart pointers share an object, you can use std::shared_ptr
:
#include <memory>
// ...
std::shared_ptr<Person> sharedPersonPtr = std::make_shared<Person>("Charlie", 40);
// 使用 shared_ptr 分配一个 Person 对象
Using smart pointers avoids many of the problems of manual memory management and provides better memory safety.
Fourth, the realization principle of new and delete
When we use dynamic memory allocation and release in C++, such as
new
anddelete
operators, we actually call a set of functions defined in the C++ standard library for memory allocation and release. These functions are called "globally configured allocation functions" and can be<new>
accessed by including the header file.
4.1. operator new
and operator delete
:
This pair of functions is used for memory allocation and deallocation of a single object. Their prototypes are:
operator new
: This function is used to allocate a memory block of the specified size on the heap and returns a pointer to the allocated memory. It takes low-level details like memory alignment into account. It can throw an exception if allocation failsstd::bad_alloc
.
operator delete
: This function is used to free the memory block previouslyoperator new
allocated by . It accepts a pointer to a memory block as a parameter, and can perform some necessary cleanup after freeing the memory.
Example usage
4.2 operator new[]
and operator delete[]
:
This pair of functions is used to allocate and free array memory. Their prototypes are:
operator new[]
: This function is used to allocate an array memory of a specified size on the heap, and returns a pointer to the allocated memory. It isoperator new
similar to but for array allocation.
operator delete[]
: This function is used to free the array memory previouslyoperator new[]
allocated by . It accepts a pointer to a memory block as a parameter, and can perform some necessary cleanup after freeing the memory.
Example usage
These functions typically call an underlying memory allocator (such as one provided by the operating system) to perform the actual allocation and deallocation. They usually guarantee some basic thread safety in a multithreaded environment.
It should be noted that although these functions work well in most cases, in some special cases, you may consider overloading these functions to implement custom memory management logic, such as implementing memory pools or Do memory usage tracking.
4.3 Supplements
In C++, the
new
anddelete
operator is mainly used to dynamically allocate and release the memory of class type objects. Of course, they can also be used to allocate and free memory for built-in data types (such as integers, floating-point numbers, etc.), but in most cases, built-in data types are usually allocated and freed automatically on the stack.
1. new
Class type processing:
When an object of a class type is created using new
the operator, it performs the following steps:
- Allocates memory of sufficient size to store objects of the class type.
- Call the constructor of the class to initialize the new object.
- Returns a pointer to the new object.
code example
class MyClass {
public:
MyClass() { std::cout << "Constructor called." << std::endl; }
~MyClass() { std::cout << "Destructor called." << std::endl; }
};
MyClass* objPtr = new MyClass; // 使用 new 创建一个 MyClass 对象
delete objPtr; // 使用 delete 释放 MyClass 对象
2. delete
Class type handling:
When using delete
the operator to free an object of a class type, it performs the following steps:
- Call the class's destructor to clean up object resources and perform necessary cleanup.
- Frees the memory occupied by the object.
code example
MyClass* objPtr = new MyClass; // 使用 new 创建一个 MyClass 对象
delete objPtr; // 使用 delete 释放 MyClass 对象
It is important to note that these steps ensure that in the case of dynamically allocated memory, objects are properly constructed and destructed at the appropriate time. For built-in data types, there is usually no need to explicitly use new
and delete
, since they are usually automatically allocated and freed on the stack.
Whether using new
or new[]
, and using delete
or delete[]
, the constructor and destructor are called for each object in the array to ensure that the objects are constructed and destructed at the correct time.