heap_stack
进程地址空间

数据段 和 bss 段
int data[] = {1, 2}; // DATA segment memory
int big_data[1000000] = {}; // BSS segment memory
// (zero-initialized)
int main() {
int A[] = {1, 2, 3}; // stack memory
}
1
2
3
4
5
6
2
3
4
5
6
data 和 bss 比栈内存大,但是访问速度较慢
| 栈 | 堆 | |
|---|---|---|
| 内存 | 连续 | allocation之内是连续的,allocation 之间是分散的 |
| 大小 | 小(linux 下 8MB,Windows 下 1MB) | 整个系统内存 |
| 如果超限 | 程序在函数入口时崩溃(很难调试) | 异常或者空指针 |
| allocation(分配) | 编译时 | 运行时 |
| 位置 | 高 | 低 |
| 线程视角 | 每个线程都有自己的栈 | 所有线程共享 |
局部变量要么在栈中,要么在 CPU寄存器里
int x = 3; // not on the stack (data segment)
struct A {
int k; // depends on where the instance of A is
};
int main() {
int y = 3; // on stack
char z[] = "abc"; // on stack
A a; // on stack (also k)
void* ptr = malloc(4); // variable "ptr" is on the stack
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
栈性能更高,但是栈的空间有限
存在栈里的数据类型:
- 局部变量
- 函数参数
- 函数返回值
- 编译器的特别指令
- 中断上下文
栈中每个对象在作用域外是无效的
int* f() {
int array[3] = {1, 2, 3};
return array;
}
int* ptr = f();
cout << ptr[0]; // Illegal memory access!! A
1
2
3
4
5
6
2
3
4
5
6
void g(bool x) {
const char* str = "abc";
if (x) {
char xyz[] = "xyz";
str = xyz;
}
cout << str; // if "x" is true, then Illegal memory access!! A
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
new/new[] 和 delete/delete[] 是C++ 关键字,用于进行动态内存分配/回收,以及在运行时对象的构造和销毁
malloc 和 free 是C关键字,分配和释放内存块(以字节为单位)
new 和 delete 的优点:
- 语言关键字:不是函数,更加安全
- 返回值类型:new 返回精准的数据类型,而 malloc 返回 void*
- 失败:new 抛异常,malloc 返回空指针
- 分配类型:new 分配的内存单元大小由编译器计算,malloc 必须手动计算分配多少字节
- 初始化:除了分配内存单元,new 还可以初始化
- 多态:带有虚函数的对象必须使用 new 分配
动态内存分配:
分配单个值:
int* value = (int*) malloc(sizeof(int)); // C
int* value = new int; // C++
1
2
2
分配 N 个元素
int* array = (int*) malloc(N * sizeof(int)); // C
int* array = new int[N]; // C++
1
2
2
分配 N 个结构体
MyStruct* array = (int*) malloc(N * sizeof(MyStruct)); // C
MyStruct* array = new MyStruct[N]; // C++
1
2
2
分配并零初始化 N 个元素
int* array = (int*) calloc(N, sizeof(int)); // C
int* array = new int[N](); // C++
1
2
2
释放单个元素
int* value = (int*) malloc(sizeof(int)); // C
free(value);
int* value = new int; // C++
delete value;
1
2
3
4
5
2
3
4
5
释放 N 个元素
int* value = (int*) malloc(N * sizeof(int)); // C
free(value);
int* value = new int[N]; // C++
delete[] value;
1
2
3
4
5
2
3
4
5
基本原则:
- new 分配的对象必须用 delete 释放
- new[] 分配的对象必须用 delete[] 释放
混用 new, new[], malloc 会导致未定义行为
delete , delete[] 用于 NULL/nullptr 空指针时不会产生错误(也是安全的)
2D 内存分配:
在栈中比较容易
int A[3][4]; // C/C++ uses row-major order: move on row elements, then columns
1
2D 动态分配和释放
int** A = new int*[3]; // allocation (pointer of pointer)
for (int i = 0; i < 3; i++)
A[i] = new int[4]; // allocation
for (int i = 0; i < 3; i++)
delete[] A[i]; // deallocation
delete[] A; // deallocation (pointer of pointer)
1
2
3
4
5
6
2
3
4
5
6
C++11 的2D动态分配和释放
auto A = new int[3][4]; // allocate 3 objects of type int[4]
int n = 3; // dynamic value
auto B = new int[n][4]; // ok
// auto C = new int[n][n]; // compile error
delete[] A; // same for B, C
1
2
3
4
5
2
3
4
5
笔记
程序不直接分配内存,而是向操作系统请求一块内存。操作系统以内存页的粒度提供内存(例如,在 linux 系统上是 4KB)
因此越界不一定导致段错误,最糟糕的情况是未定义行为
int* x = new int;
int num_iters = 4096 / sizeof(int); // 4 KB
for (int i = 0; i < num_iters; i++)
x[i] = 1; // ok, no segmentation fault
1
2
3
4
2
3
4
内存泄漏是程序不再使用动态分配的内存,但是仍然维护其执行
导致的问题:
- 非法访问:段错误,错误结果
- 未定义:段错误,错误结果
- 额外的内存消耗:潜在的段错误问题
int main() {
int* array = new int[10];
array = nullptr; // memory leak!!
} // the memory can no longer be deallocated!!
1
2
3
4
2
3
4
编辑 (opens new window)
上次更新: 2025/05/21, 06:42:57