栈"的区分。在这个例子中,`void f()` 是一个函数,当调用这个函数时,它会在栈上创建一个作用域。函数内的局部变量 `int *p` 就是在栈上分配的,它的值是一个指针,指向堆上的内存。
`new int[5]` 是在堆上动态分配了一个整型数组,大小为5。这个操作返回数组的首地址,然后赋值给 `p`。堆内存是由程序员负责管理的,意味着你需要使用 `delete[]` 来释放这个内存,否则就会造成内存泄漏。
栈内存和堆内存有以下几个关键区别:
- **生命周期**:栈内存由编译器自动管理,随着函数的进入和退出自动分配和释放;而堆内存需要程序员手动通过 `new` 和 `delete` 进行管理。
- **大小限制**:栈内存通常有限,一般几千字节到几兆字节不等,而堆内存理论上可以无限大(受限于系统可用内存)。
- **速度**:栈内存分配和释放速度快,因为其操作由硬件支持;堆内存分配较慢,因为它涉及到内存碎片管理和寻址。
- **内存连续性**:栈内存分配通常是连续的,而堆内存分配可能产生内存碎片。
1.1.1.3 内存泄漏与检测
内存泄漏是指程序在申请内存后,无法释放已申请的内存空间。常见的内存泄漏原因包括忘记释放已分配的内存、异常导致释放内存的代码未执行、指针丢失等。检测内存泄漏的方法有静态分析工具、动态分析工具以及自定义内存管理策略。
1.1.2 内存回收
在C++中,内存回收主要是指堆内存的释放。对于栈内存,编译器在函数结束时会自动回收。对于全局/静态存储区的内存,它们在程序结束时由操作系统回收。而对于堆内存,必须由程序员使用 `delete` 或 `delete[]` 对应的 `new` 或 `new[]` 操作进行回收。如果不这样做,就会导致内存泄漏。
1.1.3 避免内存泄漏的策略
- 使用智能指针(如 `std::unique_ptr` 和 `std::shared_ptr`)来自动管理对象的生命周期。
- 使用RAII(Resource Acquisition Is Initialization)原则,确保资源在构造时获取,在析构时释放。
- 使用容器类(如 `std::vector` 和 `std::map`)代替动态内存分配,因为它们会自动管理内存。
- 使用内存泄漏检测工具(如 Valgrind、LeakSanitizer 等)在开发过程中检查内存泄漏。
总结,C++的内存管理是一项核心技能,理解并掌握堆、栈、自由存储区、全局/静态存储区和常量存储区的特性,以及如何有效地分配和释放内存,是编写高效、健壮的C++程序的关键。同时,了解和应用现代C++特性,如智能指针和RAII,能显著降低内存管理的复杂性和出错概率。