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

相关文章
|
9天前
|
存储 程序员 C++
C++堆内存分配
C++堆内存分配
17 2
|
17天前
|
存储 编译器 C语言
C++中的内存管理
C++中的内存管理
25 0
|
8天前
|
存储 安全 程序员
C++语言中的内存管理技术
C++语言中的内存管理技术
|
8天前
|
存储 缓存 程序员
C++内存管理:避免内存泄漏与性能优化的策略
C++内存管理涉及程序稳定性、可靠性和性能。理解堆和栈的区别至关重要,其中堆内存需手动分配和释放。避免内存泄漏的策略包括及时释放内存、使用智能指针和避免野指针。性能优化策略则包括减少内存分配、选用合适数据结构、避免深拷贝及缓存常用数据。通过这些最佳实践,可提升C++程序的效率和质量。
|
11天前
|
存储 C语言 C++
【C++】C&C++内存管理
【C++】C&C++内存管理
|
11天前
|
安全 C++ 容器
C++ 动态内存
C++ 动态内存
16 0
|
11天前
|
编译器 程序员 C语言
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题(下)
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题
8 0
|
11天前
|
编译器 C语言 C++
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题(中)
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题
24 0
|
11天前
|
存储 程序员 编译器
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题(上)
从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题
19 0
|
15天前
|
C++