C/C++内存管理

简介: C/C++内存管理

C/C++内存管理

C++兼容C语言C++的内存管理机制和C语言是一样的,但是C语言malloc函数已经无法满足C++面对对象过程中销毁的需求,于是C++提出了新的内存管理函数newdelete

1. C/C++内存分布

将内存分成不同的区域是为了更好的管理,上面说过C++兼容C,所以内存分布都是一样的:

171c05f057cb2ef524b5321998c64dde.png五大分区:

  1. 栈区:又叫堆栈,用于存储非静态局部变量、函数参数、返回值等等,是向下增长的
  2. 内存映射段: 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信
  3. 堆区:用于程序运行时动态内存分配,堆是可以上增长的
  4. 数据段:数据段用于存储全局数据和静态数据
  5. 代码段:代码段用于存储可执行的代码和只读常量

内存中还存在内核空间,但普通用户代码无法读写

2. C++动态内存管理

内存管理是为了对内存进行分类,使操作系统对内存能有更让的管理,C++提出了newdelete操作符进行动态内存管理,下面我们来讲讲使用细节

2.1 new和delete操作内置类型

代码演示:

void Test()
{
  int* ptr1 = new int; //申请一个整型,只是开空间
  delete ptr1; //释放
  double* ptr2 = new double(6.66); //申请一个浮点型,并初始化为6.66
  delete ptr2; //释放
  int* ptr3 = new int[8]; //申请8个int类型的空间
  delete[] ptr3; //释放8次
}

2.2 new和delete操作自定义类型

代码演示:

class A
{
  A(int a = 12)
    :_a(a)
  {
    cout << "A()" << endl;
  }
  ~A()
  {
    cout << "~A()" << endl;
  }
private:
  int _a;
};
int main()
{
  //new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数
  A* p1 = (A*)malloc(sizeof(A)); //开空间
  A* p2 = new A(12); //开空间并初始化
  free(p1);
  delete p2;
  //内置类型是几乎是一样的
  int* p3 = (int*)malloc(sizeof(int));
  int* p4 = new int;
  free(p3);
  delete p4;
  A* p5 = (A*)malloc(sizeof(A) * 10); //开10个A类对象空间
  A* p6 = new A[10]; //开10个A类对象空间
  free(p5);
  delete[] p6;
  return 0;
}

总结:

  1. new不需要像malloc那样进行空指针判断,也不需要进行类型转换
  2. delete需要配套使用,比如new int 使用 deletenew int 使用 delete[]
  3. newdelete都可以用于自定义类型,会分别调用自定义类型的构造函数析构函数
  4. new/deletemalloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数析构函数
  5. malloc 对应freenew 对应 delete,一定要搭配使用,避免引发问题

3. operator new 和 operator delete函数

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

Visual studio 2019中operator new底层实现:

void* __CRTDECL operator new(size_t const size)
{
  for (;;)
  {
    if (void* const block = malloc(size))
    {
      return block;
    }
    if (_callnewh(size) == 0)
    {
      if (size == SIZE_MAX)
      {
        __scrt_throw_std_bad_array_new_length();
      }
      else
      {
        __scrt_throw_std_bad_alloc(); //抛出异常
      }
    }
    // The new handler was successful; try to allocate again...
  }
}

Visual studio 2019中operator delete底层实现:

void __CRTDECL operator delete(void* const block, size_t const) noexcept
{
  operator delete(block);
}
void __CRTDECL operator delete(void* const block) noexcept
{
#ifdef _DEBUG
  _free_dbg(block, _UNKNOWN_BLOCK);
#else
  free(block);
#endif
}

Visual studio 2019中operator new[]底层实现:

void* __CRTDECL operator new[](size_t const size)
{
  return operator new(size); //原理调用的size次operator new函数
}

Visual studio 2019中operator delete底层实现:

void __CRTDECL operator delete[](void* const block) noexcept
{
  operator delete(block);
}
void __CRTDECL operator delete[](void* const block, size_t const) noexcept
{
  operator delete[](block);
}

4. new 和 delete实现原理

4.1 内置类型

如果申请的是内置类型的空间,newmallocdeletefree基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL

4.2 自定义类型

new的原理:

  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数,完成对象的构造

delete的原理:

  1. 在空间上执行析构函数,完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间

new T[N]的原理:

  1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对

象空间的申请

  1. 在申请空间上执行N次构造函数

delete[]的原理:

  1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
  2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

5. 定位new

定位newnew的新用法,是为了对已经开辟但没有初始化的空间进行初始化

5.1 基本语法

定位new表达式是:在已分配的原始内存空间中调用构造函数初始化一个对象

使用格式:new(指针)type或者new(指针)type(初始化列表)

代码使用:

class A
{
public:
  A(int a)
    :_a(a)
  {
    cout << "A()" << endl;
  }
  ~A() {
    cout << "~A()" << endl;
  }
private:
  int _a;
};
int main()
{
  A* p = (A*)malloc(sizeof(A));
  if (p == nullptr) {
    perror("malloc is failed");
    exit(-1);
  }
  new(p)A(1); //定位new,对已经定义的对象初始化
  return 0;
}

5.2 使用场景

使用场景:一般配合内存池使。因为内存池分配出的内存没有初始化,所以如果定义自定义类型对象,需要使用new的定义表达式进行显示调用构造函数进行初始化

C/C++内存管理到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!

文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正

目录
相关文章
|
14天前
|
存储 程序员 编译器
玩转C++内存管理:从新手到高手的必备指南
C++中的内存管理是编写高效、可靠程序的关键所在。C++不仅继承了C语言的内存管理方式,还增加了面向对象的内存分配机制,使得内存管理既有灵活性,也更加复杂。学习内存管理不仅有助于提升程序效率,还有助于理解计算机的工作原理和资源分配策略。
|
3月前
|
存储 缓存 编译器
【硬核】C++11并发:内存模型和原子类型
本文从C++11并发编程中的关键概念——内存模型与原子类型入手,结合详尽的代码示例,抽丝剥茧地介绍了如何实现无锁化并发的性能优化。
206 68
|
12天前
|
安全 C语言 C++
彻底摘明白 C++ 的动态内存分配原理
大家好,我是V哥。C++的动态内存分配允许程序在运行时请求和释放内存,主要通过`new`/`delete`(用于对象)及`malloc`/`calloc`/`realloc`/`free`(继承自C语言)实现。`new`分配并初始化对象内存,`delete`释放并调用析构函数;而`malloc`等函数仅处理裸内存,不涉及构造与析构。掌握这些可有效管理内存,避免泄漏和悬空指针问题。智能指针如`std::unique_ptr`和`std::shared_ptr`能自动管理内存,确保异常安全。关注威哥爱编程,了解更多全栈开发技巧。 先赞再看后评论,腰缠万贯财进门。
|
2月前
|
存储 程序员 编译器
什么是内存泄漏?C++中如何检测和解决?
大家好,我是V哥。内存泄露是编程中的常见问题,可能导致程序崩溃。特别是在金三银四跳槽季,面试官常问此问题。本文将探讨内存泄露的定义、危害、检测方法及解决策略,帮助你掌握这一关键知识点。通过学习如何正确管理内存、使用智能指针和RAII原则,避免内存泄露,提升代码健壮性。同时,了解常见的内存泄露场景,如忘记释放内存、异常处理不当等,确保在面试中不被秒杀。最后,预祝大家新的一年工作顺利,涨薪多多!关注威哥爱编程,一起成为更好的程序员。
|
4月前
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
88 3
|
4月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
280 4
|
5月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
295 22
|
5月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
5月前
|
存储 C语言 C++
【C++打怪之路Lv6】-- 内存管理
【C++打怪之路Lv6】-- 内存管理
71 0
【C++打怪之路Lv6】-- 内存管理
|
5月前
|
存储 C语言 C++
【C/C++内存管理】——我与C++的不解之缘(六)
【C/C++内存管理】——我与C++的不解之缘(六)