目录

前言

一、C/C++中程序内存区域划分

二、C++使用new申请堆内存

1.new和delete的使用

2.new和delete的底层实现


前言

hello~❥(ゝω・✿ฺ) 大家好呀!欢迎能够看我的这一篇关于C++的学习笔记,让我们一起进步吧~

我们首先要了解到的是C/C++下的内存管理,然后由C语言用malloc在堆上申请内存过渡到C++语言用new在堆上申请内存观察这两者的区别和差异,以及探究new的底层实现原理!

一、C/C++中程序内存区域划分

我们知道,一份源文件经过预处理、编译、汇编、链接步骤之后,就会变成一份二进制文件。此时其是存储在磁盘上的。当我们点击运行时,其属性加载进OS的PCB,排入cpu的运行队列成为一个进程。而此时此程序相关的二进制代码和数据才会进内存,但是此内存是虚拟内存,通常大小只有4g。

此时细化给程序分配的内存就如下图所示:

比如,区分如下变量内存空间,判断在那个区间:

int a = 1;
static int b = 2;
int main()
{int c = 3;int* d = (int*)malloc(sizeof(int));if (d == NULL){perror("malloc");return 0;}*d = 4;char e[] = "abcd";const char* f = "abcd";cout << a << b << c << *d << e << f << endl;free(d);d = nullptr;return 0;
}

a是全局变量,所以在数据段(全局数据);b是静态全局变量,所以在数据段(静态数据);c是局部变量,在栈帧中开辟,所以在栈上;d是地址,由栈指向堆内某块内存,所以d在栈上;*d是指针解引用,指向堆内存,所以在堆上;e同样是一个地址,所以在栈上;*e此时指向栈内存,因为在之前编译器做的就是将“abcd”从常量区拷贝到栈上给e数组;f是地址,所以在栈上;*f此时指向常量,常量区位于代码段(只读常量)。

了解了内存分配后,我们就可以知道平时c语言使用malloc函数的时候就是向堆内存申请空间。但是C++增加了自定义类型之后,我们想在堆上给自定义类型开空间怎么办呢?同时自定义类型设计构造函数以及初始化的问题,这些该如何解决呢?C++就推出了new操作符。

二、C++使用new申请堆内存

1.new和delete的使用

如图C语言中的malloc和free配对一样,C++中新增了new和delete进行配对。同样的是在堆上开辟空间,另一个就是在堆上释放空间。

new:

数据类型 变量名 = new 数据类型;

在new数据类型后加(n)表示给此堆变量赋初始值

在new数据类型后加[n]表示是数组

数组类型赋给初始值:(注意C++11支持)

= new 数据类型[n]{...}    ...中内置类型是0~n个数据,自定义类型必须满(一个类型需要多次赋值就在里面加{})

delete:

delete 变量名;

如果是数组

delete[] 变量名;

注意:

new  对应 delete  new [] 对应 delete[]   必须一一对应,不对应的话会出问题。

对于内置类型,delete可以等价于free

比如如下内置类型使用new申请堆空间:

int main()
{int* a = new int;int* b = new int(1);int* c = new int[3];int* d = new int[3]{ 1, 2, 3 };cout << *a << endl;cout << *b << endl;for (int i = 0; i < 3; i++){cout << c[i] << " ";}cout << endl;for (int i = 0; i < 3; i++){cout << d[i] << " ";}cout << endl;delete a;delete b;delete[] c;delete[] d;return 0;
}

可以通过上面的代码发现,new和malloc等的区别就是不用检查是否传回来是空和不用强转类型,那么new是如何检查能否申请成功的呢?利用的是异常处理。--异常处理

比如可以向虚拟内存申请大概2g的空间,那么就会异常处理(x32位平台下):

int main()
{try{char* a = new char[1024u * 1024u * 1024u * 2 - 1];delete[] a;}catch (const exception& e){cout << e.what() << endl;}return 0;
}

其中try和catch就是接收抛出的异常,如果存在异常就进入下面的catch语句中,what函数就输出错误:

-- 分配不当 --

那么初看对于内置类型,new与delete和malloc与free也没有多大的区别,最多就是malloc如果申请不到堆内存就返回NULL,而new的处理就是抛出异常。但是针对于自定义类型,这个差异就会非常大了:

class Test
{int _num;
public:Test(int num = 0):_num(num){cout << "Test()构造" << endl;}~Test(){cout << "Test()析构" << endl;}
};int main()
{Test* t = new Test;Test* t2 = new Test[3]{ 1, 2, 3 };delete t;delete[] t2;return 0;
}

可以发现,new不仅仅在堆内申请空间,并且也调用了自定义类型的构造函数。(赋的有初始值就调用对应的构造函数,否则调用默认构造函数),然后delete会在释放堆内存之前,先调用析构函数,然后才会释放空间。

2.new和delete的底层实现

new和delete终究是两个操作符,而malloc是一个函数。那么new和delete是如何完成申请空间的同时调用构造函数和析构函数呢?

首先,就不得不说两个重要的系统实现的全局函数:operator new 和 operator delete:

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,
尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}

上面是两个函数的底层实现,可以大致的看出来实际上operator new用malloc申请堆内存,然后做了一些异常处理,同理,operator delete也是用free进行释放空间的。

然后我们可以查看其汇编代码:

就可以发现,new在调用operator new函数后即申请空间后就会去调用构造函数。同理,delete也是先调用的~析构,之后在释放空间。

综上:

new:

调用operator new,里面malloc存在的意义:1.帮助new开空间,封装malloc,为了符合C++new的失败机制 -- 失败抛异常之后。之后调用构造函数。

delete:

调用析构函数清理,然后调用operator delete,里面封装了free,释放空间。

未完待续.......

【C++】内存管理到用new申请堆内存相关推荐

  1. 【转】C#的内存管理:堆栈、托管堆与指针

    在32位的Windows操作系统中,每个进程都可以使用4GB的内存,这得益于虚拟寻址技术,在这4GB的内存中存储着可执行代码.代码加载的DLL和程序运行的所有变量,在C#中,虚拟内存中有个两个存储变量 ...

  2. malloc申请堆内存

    1.malloc申请的空间,是否记录空间大小?若是记录,那所记录的空间大小在哪呢?为什么利用free释放不需要空间大小参数呢? malloc申请空间时,记录其空间大小(其空间上方,有一个数据头,头部信 ...

  3. Dreamwear如何创建javascript_内存管理+如何处理4种常见的内存泄漏

    JavaScript是如何工作的:内存管理+如何处理4种常见的内存泄漏 潮水自会来去,但心志得坚若磐石.即便成不了那根定海神针,也至少不是那随意被拍上岸的野鬼游魂.by 一枚热汤圆 几周前,我们开始了 ...

  4. 【Unity】Unity内存管理与优化(一)内存域、堆栈、垃圾回收、内存泄漏、内存碎片

    文章目录 Unity内存 内存域 - 托管域 - 本地域 - 外部库 - 跨桥操作 堆和栈 - 栈 - 堆 - 堆栈的使用 垃圾回收 - Mono内存分配过程 - 内存泄漏 - 内存碎片 - 运行时垃 ...

  5. java 内存管理_高性能Java代码之内存管理

    本文通过几个方面,来介绍Java代码的内存管理. 有的代码,GC根本就回收不了,直接系统挂掉.GC是一段程序,不是智能,他只回收他认为的垃圾,而不是回收你认为的垃圾. GC垃圾回收: Grabage ...

  6. 内存管理(二)-- linux 预留内存几种方法

    日常开发过程可能要预留一段物理内存出来提供特殊场景使用(独占一段内存不被系统所使用). 本文讲解3种预留内存的方法,以及对预留内存的使用. 文章目录 一.memblock方式预留内存 1.1 memb ...

  7. 操作系统核心原理-5.内存管理(中):分页内存管理

    在上一篇介绍的几种多道编程的内存管理模式中,以交换内存管理最为灵活和先进.但是这种策略也存在很多重大问题,而其中最重要的两个问题就是空间浪费和程序大小受限.那么有什么办法可以解决交换内存存在的这些问题 ...

  8. 内存管理器(十)kernel内存管理----数据结构

    内存管理器(十) kernel内存管理----概况与数据结构 前言 正式开始学习内核的内存管理了,先学习下接口函数,每一个例字都必须写内核模块实验,然后深入到函数的内部研究源码,最后写写练习的小程序. ...

  9. 内存管理模拟程序c语言,C语言 内存管理详解

    本文出自: 伟大的Bill Gates曾经失言: 640K ought to be enough for everybody -Bill Gates 1981. 程序员们经常编写内存管理程序,往往提心 ...

最新文章

  1. 图形化的Redis监控系统redis-stat安装
  2. 在Word中调用外部程序两法
  3. Android Service 服务(二)—— BroadcastReceiver
  4. 温故而知新-面向对象的PHP
  5. CTFshow php特性 web115
  6. oracle层次查询中prior与自上而下、自下而上查询
  7. 08 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(下)
  8. java实现文件上传和文件查看、下载
  9. 51单片机usb烧录电路_STC51单片机ISP自动下载电路设计
  10. Abbot和Marathon比较
  11. 3dsMax一渲染就卡住、3DMAX渲染完卡死怎么办?解决方法来了
  12. DM8168 Uboot使用EMAC1(TI源码使用默认的EMAC0)
  13. Moblin v2开发环境设置——创建一个新应用程序
  14. android 5.0官方安装包,Android5.0刷机包怎么安装 Android5.0刷机包安装教程
  15. GlobalSign 发布了即将要修改代码签名证书的重要通知
  16. 首个实时全球空中交通监控系统在北大西洋上空全面投入运行和试用
  17. 2023程序员今年的一些现状
  18. 关于Direct3D11中字体的思考
  19. 不懂就问,机器人做核酸是一种什么体验?|一周AI新闻
  20. c语言学籍管理系统设计,c语言学籍信息管理系统设计

热门文章

  1. 用C#开发的双色球走势图(二)
  2. java mvc设计模式_JavaEE知识点:MVC设计模式
  3. 有关windows黑屏的解决办法
  4. 第7节包传输与流传输
  5. 手机访问电脑上的本地网页
  6. Babel是如何读懂JS代码的
  7. Hippo4J v1.3.1 发布,增加 Netty 监控上报、SpringCloud Hystrix 线程池监控等特性
  8. Aosp源码编译及pixel手机刷机
  9. 【整理】昆虫细胞培养方法Protocol参考文献
  10. 认知跃迁,由生疏到成熟的四个关键!