C++中的动态内存管理

简介: C++中的动态内存管理

C++中的动态内存管理

1. 内存分布与虚拟地址空间

每一个加载到内存中的进程,都有一个虚拟地址空间,再经过页表映射到物理内存空间。

2. C语言的动态内存管理

malloc:动态开辟空间,不会初始化。

calloc:动态开辟空间+初始化。

realloc:堆动态开辟的空间进行重新分配。

free:释放动态开辟的空间。

上面这些都是函数调用。

3. C++的动态内存管理

new:动态申请内存

delete:释放内存

批量动态内存管理:new []delete []

int main()
{
  int* a = new int;
  int* b = new int[10]; // new 10个int类型的元素
  int* c = new int(10); // 初始化为10
  delete a;
  delete[] b;
  delete c;
  return 0;
}

newdelete是关键字!!

new在申请自定义类型的空间时,在申请空间后会自动调用其构造函数进行初始化;delete在释放自定义类型的空间时,会先调用它的析构函数,再释放空间。

4. newdelete的实现原理

1. operator newoperator delete函数

newdelete是用户进行动态内存申请和释放的操作符(关键字),而operator newoperator delete是系统提供的全局函数new在底层调用operator new全局函数来动态申请空间,delete在底层通过operator delete全局函数来释放空间。

实际上,operator new 是通过调用malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足时的应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终也是通过调用free来释放空间的。

operator newoperator delete函数对于自定义类型不会调用其构造/析构函数。

2. 重载operator newoperator delete函数

一般情况下不需要对 operator newoperator delete进行重载,除非在申请和释放空间的时候有某些特殊的需求。比如:在使用newdelete申请和释放空间时,打印一些日志信息,或者使用内存池分配空间,不需要operator new直接访问堆。

3. newdelete的实现原理

new:先调用 operator new申请空间(operator new又调用malloc ),然后对于自定义类型会调用它的构造函数初始化。

delete对于自定义类型先调用其析构函数释放资源,然后调用 operator delete函数释放空间(operator delete又调用 free)。

new [N]:先调用 operator new[]申请空间(operator new[]调用operator new ),然后对于自定义类型会调用N次它的构造函数初始化。

delete []:对于自定义类型先调用N次其析构函数释放资源,然后调用 operator delete[]函数释放空间(operator delete[]调用 operator delete)。

5. placement-new

placement-new是指在已分配的动态内存空间中调用构造函数初始化一个对象。 一般是配合内存池使用,因为内存池申请的内存并没有初始化,所以使用placement-new去初始化自定义类型。

使用方式:

class T
{
public:
  T(int a)
    :a_(a)
  {}
  ~T()
  {}
private:
  int a_;
};
int main()
{
  // 正常 new, delete
  T* t = new T(10);
  delete t;
  // 只申请空间,并没有初始化!
  T* t1 = (T*)malloc(sizeof(T));
  assert(t1);
  // 使用 placement-new 初始化 t1
  new(t1)T(20);
  t1->~T();
  free(t1);
  return 0;
}

6. malloc/freenew/delete的区别(面试题)

  1. malloc/new函数调用,而new/delete关键字
  2. new申请空间可以进行初始化。(不过calloc也可以)
  3. malloc要传参指定需要的空间大小,而new只需要给类型就可以。
  4. malloc的返回值是 void*,要进行强转,而new不需要,直接返回对应类型的指针
  5. malloc申请空间失败返回NULL,而**new失败抛异常**。
  6. 对于自定义类型的区别!!

异常捕获:

int main()
{
  try
  {
    // 10G
    int* p = new int[1024*1024*1024*10];
    // ...
  }
  catch(const exception& e)  //  捕获异常信息
  {
    cout << e.what() << endl;  // 打印异常信息
  }
  return 0;
}

7. 内存泄漏

一般有两类内存泄漏:

  1. 动态申请的内存空间没有释放,指向这块内存的指针丢了。
  2. 申请的系统资源没有释放!如文件描述符fd,网络套接字socketfd等。

避免内存泄漏:

  1. 良好的代码规范。
  2. 使用RAII来管理资源。(智能指针)
  3. 使用内存泄漏检测工具。
  4. 动态申请的内存空间没有释放,指向这块内存的指针丢了。
  5. 申请的系统资源没有释放!如文件描述符fd,网络套接字socketfd等。

避免内存泄漏:

  1. 良好的代码规范。
  2. 使用RAII来管理资源。(智能指针)
  3. 使用内存泄漏检测工具。

最后挂个链接,欢迎一起学习,一起进步!https://xxetb.xet.tech/s/4G6TWG

相关文章
|
1月前
|
存储 Java 编译器
C++:内存管理|new和delete
C++:内存管理|new和delete
|
1月前
|
存储 算法 编译器
【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
【C++ 内存管理 重载new/delete 运算符 新特性】深入探索C++14 新的/删除的省略(new/delete elision)的原理与应用
47 0
|
5天前
|
存储 人工智能 程序员
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
35 1
|
1月前
|
存储 Linux C语言
【C++练级之路】【Lv.5】动态内存管理(都2023年了,不会有人还不知道new吧?)
【C++练级之路】【Lv.5】动态内存管理(都2023年了,不会有人还不知道new吧?)
|
1月前
|
安全 程序员 C++
【C++ 基本知识】现代C++内存管理:探究std::make_系列函数的力量
【C++ 基本知识】现代C++内存管理:探究std::make_系列函数的力量
102 0
|
1月前
|
存储 Linux 程序员
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
【Linux C/C++ 堆内存分布】深入理解Linux进程的堆空间管理
79 0
|
1月前
|
算法 Java C++
【C/C++ 内存知识扩展】内存不足的可能性分析
【C/C++ 内存知识扩展】内存不足的可能性分析
12 0
|
1月前
|
存储 算法 Linux
深入理解Linux内存管理brk 和 sbrk 与以及使用C++ list实现内存分配器
深入理解Linux内存管理brk 和 sbrk 与以及使用C++ list实现内存分配器
37 0
|
1月前
|
缓存 Linux iOS开发
【C/C++ 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南
【C/C++ 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南
66 1
|
1月前
|
存储 安全 算法
【C/C++ std::memory_order 枚举】掌握 C++ 内存模型:深入理解 std::memory_order 的原理与应用
【C/C++ std::memory_order 枚举】掌握 C++ 内存模型:深入理解 std::memory_order 的原理与应用
51 0