C++基础之内存管理

发布于:2024-10-16 ⋅ 阅读:(12) ⋅ 点赞:(0)

目录

1,堆(heap)使用要点总结

2,栈(stack)使用要点总结

3,RAII思想使用总结

4,常用的优化内存管理技术

4.1,内存池

4.2,智能指针 

4.3,内存泄露检测工具 


1,堆(heap)使用要点总结

  • 动态分配内存的区域,使用 new 和 delete 或 malloc 和 free 进行内存分配和释放。如果没有手动释放,可能会造成内存泄漏。
int* ptr = new int; // 分配一个int大小的内存
*ptr = 10; // 初始化内存
delete ptr; // 释放内存
//使用new[]创建数组
int* arr = new int[10]; // 分配一个int数组
for (int i = 0; i < 10; ++i) {
    arr[i] = i;
}
delete[] arr; // 释放数组
  • new 和 delete 是 C++ 中的运算符,malloc 和 free 是 C 语言中的函数,虽然在 C++ 中也可以使用,但通常更推荐使用newdelete,因为它们支持构造和析构操作,这对于对象的生命周期管理至关重要。
int* ptr = (int*)malloc(sizeof(int)); // 分配内存
*ptr = 10; // 初始化内存
free(ptr); // 释放内存

2,栈(stack)使用要点总结

  • 栈内存管理是函数调用过程中用于存储本地变量和调用数据的区域。
  • 栈是后进先出(LIFO)的结构。在大多数计算机架构中,栈从高地址向低地址增长。
  • 每次函数调用时,会将参数和返回地址压入栈中。函数执行结束时,栈指针会复位到调用该函数前的位置,释放该函数使用的栈空间。
  • 栈上的内存分配和释放非常高效,仅需移动栈指针。
  • 栈上的内存分配和释放相对简单,只需移动栈指针即可。

3,RAII思想使用总结

  • RAII 是 C++ 中管理资源的一种惯用手法,保证资源在对象生命周期内的正确分配和释放。
  • 对象可以存储在栈上或堆上,但在许多情况下,对象不应存在栈上,例如对象非常大或大小在编译时无法确定。
  • RAII 的核心思想是将资源的获取与对象的生命周期绑定,在对象的构造函数中获取资源,并在析构函数中释放资源。
  • RAII思想除了广泛应用于内存管理,还可用于文件句柄、同步锁等关键资源的管理。
#include <fstream>

class FileHandle {
public:
    FileHandle(const char* filename) {
        file_.open(filename);
    }

    ~FileHandle() {
        if (file_.is_open()) {
            file_.close();
        }
    }

    // 禁止复制构造和赋值操作
    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;

private:
    std::ofstream file_;
};

 在上述示例中,FileHandle类在构造函数中打开文件,并在析构函数中关闭文件。这样,只要FileHandle对象的生命周期结束,文件就会自动关闭,从而避免了资源泄漏。

4,常用的优化内存管理技术

4.1,内存池

内存池是一种优化动态内存分配的技术,它预先分配一大块内存,并从中分配小块内存给请求者。这样可以减少内存碎片,并提高内存分配的效率。

class MemoryPool {
public:
    MemoryPool(size_t poolSize) {
        pool_ = new char[poolSize];
        freeList_ = pool_;
    }

    ~MemoryPool() {
        delete[] pool_;
    }

    void* allocate(size_t size) {
        // 实现内存分配逻辑
    }

    void deallocate(void* pointer) {
        // 实现内存释放逻辑
    }

private:
    char* pool_;
    char* freeList_;
};

,4.24.2,智能指针 

智能指针是一种自动管理动态分配内存的类,可以自动释放内存,避免内存泄漏。C++11引入了几种智能指针,如std::unique_ptrstd::shared_ptrstd::weak_ptr

#include <memory>

std::unique_ptr<int> uniquePtr(new int(10));
std::shared_ptr<int> sharedPtr(new int(20));

4.3,内存泄露检测工具 

C++有多种工具可以帮助检测内存泄漏,如Valgrind、AddressSanitizer等。这些工具可以在程序运行时监控内存分配和释放,帮助我们定位内存泄漏的位置,快速排查解决问题。

  • Valgrind

开源框架,通过模拟CPU环境来检测程序中的内存问题。Memcheck是最常用的模块,用于检测内存泄漏、内存越界等问题。运行命令如下

valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./program_name

优点:

能够检测多种内存问题,如内存泄漏、内存越界等;

提供详细的错误报告,包括泄漏的大小和在代码中的位置。

缺点:

运行被检测的程序时会显著变慢。

  • AddressSanitizer(ASAN)

ASAN 是一个快速的内存错误检测器,它可以检测使用已释放内存、堆内存越界、栈内存越界等问题。它通过编译时插桩来检测错误。使用时需要在编译语句中增加开启:

g++ -fsanitize=address -g test_program.cpp -o test_program

优点:

检测速度快,对程序性能的影响较小;

可以与现有的调试工具一起使用。

缺点:

可能会增加编译后的程序大小。