前言:
内存管理
内存分布通常可以分为以下几个区域:
栈(Stack):栈用于存储局部变量、函数参数和函数返回地址等信息。且向下增长
堆(Heap):堆用于动态分配内存,即通过 new
、malloc
等关键字在运行时分配内存。
数据段 (全局/静态存储区 Global/Static Storage Area):全局变量和静态变量在程序启动时被分配在全局/静态存储区域。全局变量在整个程序执行期间都存在,而静态变量具有局部作用域(局部静态变量,例如在函数中声明的静态变量)但生命周期与程序执行期间一样长。全局/静态存储区的内存分配在程序启动时完成,在程序结束时释放。
常量存储区(Constant Storage Area):常量字符串等常量数据存储在常量存储区,其内容在程序运行期间不可改变。常量存储区的内存通常位于程序的可执行文件中,因此称为常量存储区。
代码区(Code Area):**代码区存储程序的机器指令,即可执行代码。**代码区通常位于可执行文件的某个特定部分,在程序执行时被加载到内存中供CPU执行。
我们来看一下这些例子:
int globalVar = 1;//globalVar是全局变量,存在数据段上
static int staticGlobalVar = 1;//staticGlobalVar是静态变量,存在数据段上
int main(){
static int staticVar = 1;//staticVar局部静态变量,存在数据段上
int localVar = 1;//localVal是局部变量,在栈上
int num1[10] = { 1, 2, 3, 4 };//num1局部变量,在栈上
//char2是数组名,首元素地址,存在栈上;
//*char2,实际上是字符'a'且字符串"abcd"也是在栈中,所以*char2同样存在栈中
char char2[] = "abcd";
//pChar3是指针变量,存放在栈中;
//因为加了const修饰,所以字符串常量"abcd"存储在常量存储区,只读操作,不可修改;如果没有const修饰,就存在栈中,因此加了const修饰后,*pChar3储存在常量区
const char* pChar3 = "abcd";
//ptr1是指针变量,存在栈中;*ptr1是分配的内存,存在堆中
int* ptr1 = (int*)malloc(sizeof(int) * 4);
free(ptr1);
}
C 中的动态内存管理
动态内存分配函数:C 中的动态内存分配函数包括 malloc()
, calloc()
, realloc()
。例如:
int* ptr = (int*)malloc(sizeof(int) * 10); // 分配一个包含 10 个整数的内存块
释放动态分配的内存:使用 free()
函数可以释放动态分配的内存,防止内存泄漏。例如:
free(ptr); // 释放动态分配的内存
C++ 中的动态内存管理
动态内存分配运算符:C++ 中使用 new
运算符来动态分配内存。例如:
int* ptr1 = new int(1); // 分配一个整型并初始化
int* ptr2 = new int[10]; // 分配一个包含 10 个整数的内存
int* ptr3 = new int[5] = {1, 2, 3, 4, 5};// 分配五个整型并初始化
释放动态分配的内存:使用 delete
运算符释放动态分配的内存,与 C 中的 free()
相对应。例如:
// 释放动态分配的内存
delete ptr1;
delete[] ptr2;
delete[] ptr3;
new
和delete
是用户进行动态内存申请和释放的操作符,operator new
和operator delete
是系统提供的全局函数,new
在底层调用operator new
全局函数来申请空间,delete
在底层通过operator delete
全局函数来释放空间。
而operator new
和 operator delete
在大多数系统中,底层会使用 malloc
和 free
来分配或释放内存,但在一些特定的环境中,可能会使用其他的内存分配和释放函数。
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
一般的 new
表达式会分配内存并在该内存上构造对象,而定位 new
表达式则允许你提供一个已经分配的内存地址来构造对象。
定位new表达式的基本语法:
new (pointer) Type(initializer)
其中,pointer
是一个指向要构造对象的内存位置的指针,Type
是要构造的对象类型,initializer
是可选的初始化参数。
以下是一个示例,演示了如何使用定位new表达式:
#include
class MyClass {
public:
MyClass(int value) : m_value(value) {
std::cout << "Constructing MyClass with value: " << m_value << std::endl;
}
private:
int m_value;
};
int main() {
// 分配内存
char buffer[sizeof(MyClass)];
// 在给定内存位置上构造对象
MyClass* obj = new (buffer) MyClass(42);
return 0;
}
在这个示例中,我们首先分配了足够大的内存缓冲区(buffer
),然后使用定位new表达式在该缓冲区上构造了一个 MyClass
对象。注意,我们在构造对象后,可以像常规指针一样使用该对象。
定位new表达式的一个常见用途是在特定的内存位置上构造对象,比如在实现自定义内存池或者对象池时。
不同点:
malloc
和 free
是 C 语言中的函数,而 new
和 delete
是 C++ 中的操作符。
malloc
分配的内存不会初始化,而 new
可以初始化。但是需要注意,对于内置类型(如 int
、double
等),new
分配的内存并不会被初始化。
malloc
需要手动计算空间大小并传递,而 new
不需要,因为它知道要分配的类型的大小。对于数组,new
可以使用 []
指定对象个数。
malloc
的返回值是 void*
,需要显式转换为目标类型,而 new
返回的是所分配类型的指针,不需要显式转换。
当内存不足时,malloc
返回 NULL
,需要检查是否为 NULL
,而 new
抛出 std::bad_alloc
异常。
对于自定义类型,malloc
和 free
只是分配和释放内存,并不会调用构造函数和析构函数。而 new
在分配内存后会调用构造函数初始化对象,delete
在释放内存前会调用析构函数。
共同点: