龙空技术网

CPU眼里的:malloc vs new

阿布编程 1890

前言:

而今你们对“开机new cpu”可能比较珍视,兄弟们都想要分析一些“开机new cpu”的相关资讯。那么小编也在网上汇集了一些有关“开机new cpu””的相关知识,希望你们能喜欢,看官们快快来了解一下吧!

用CPU的视角,重新解读 malloc 和 new 之间的区别。让我们一起震惊面试官吧

请问,如何申请一段内存?答案或许显而易见!是调用 malloc 函数;那如何为一个类对象,申请内存呢?答案似乎也不难!是使用:new。既然都是申请内存,那为什么要搞两套接口呢?这两套接口之间,又有什么差异呢?今天,就让我们用CPU的视角,重新认识一下它们。

01

malloc 的工作原理

先写一个最简单的 malloc 测试函数:

void* func_1(){    return malloc(4);}

通过 Compiler Explorer,得到它们的汇编指令:

代码十分简单,对应的汇编指令也只有两条而已。

第一条指令:把数值 4 赋给寄存器 edi,很显然,这是为后面的函数调用,准备参数。更详细的解读,还可以参看上期的内容:《CPU眼里的:参数传递》

第二条指令:就是调用函数:malloc,结合传递的参数值 4,我们可以很容易猜出:这是要申请一个 4 字节大小的内存块。这样看来,malloc 是一个非常单纯的函数:输入所需内存的大小,它就可以帮我们申请相应大小的内存块。

02

new 的工作原理

让我们再看看,malloc的同门兄弟:new

先编写一个最简单的类:A,然后,写一个最简单的函数,用来申请一个类 A 的对象。

class A{public:    A()    {        x = 1;        y = 2;    }    int x, y;};A* func_2(){    return new A();}

虽然只有一行代码,却对应了4条汇编指令

不要怕,它们除了样子怪一点,其实并没有什么过人之处!

先看前两条指令:

mov edi, 8call operator new(unsigned long)

是不是跟调用:malloc 函数,非常相似?以此类推,第一条指令,还是传递参数值:8;因为类 A 仅有 2 个 int 类型的成员变量,所以 类 A 的大小是 8 个字节,非常合理。

然后就是调用一个叫做:operator new 的函数,如此逆天的名字,真的很让人怀疑自己的知识储备

但在CPU眼里,它根本就不是一个名字,而只是一个函数首地址而已。

当然这个函数不是我们写的,而是库函数为我们提前预备好的:内存分配函数。如果你不放心的话,也可以重写这个函数,具体实现,甚至可以直接调用:malloc

void* operator new(unsigned long size){    return malloc(size);}

具体的申请内存工作,就由 malloc 或 相应的库函数帮我们代劳了。至于内存管理/分配/回收的具体办法,不是本文的讨论重点。

简而言之:在标识好被分配出去的内存后,内存分配就完成了。

如果是 malloc,就可以收工了;但 new 可不行,别忘了:类对象是需要初始化的!没错,就是要调用:构造函数,所以剩下的两条指令,也很容易解释了。

mov rdi, raxcall A:A()

第一条指令,把申请到的内存地址,传递给寄存器:rdi,还记得上期的视频《CPU眼里的:构造函数》吗?调用构造函数,也是需要传递:this 指针的。完成这个 this 指针的传递,我们就可以调用:类 A 的构造函数了。也就是将:1、2 写入到相应的内存中。

至此,new 操作全部完成!真不愧是 C++ 呀,如此简单的3个字母,居然隐藏着这么多的秘密

03

free & delete

同样的方法,我们可以很容易的猜出:free 和 delete 之间差异:

free 是 malloc 的反向操作,也是一个纯函数接口。不过它的用途不是:申请内存,而是释放、归还刚才申请的内存。

同样,delete 是 new 的反向操作。

它也包含了两个操作:

首先,调用类 A 的析构函数:

然后,就可以跟 free 一样,释放、归还:类 A 对象所占据的内存空间。

04

总结

1.malloc 和 free 都是单纯的函数,用来申请内存和归还内存

2. new 包含了两个操作:第一个操作:跟 malloc 类似,也是申请内存。第二个操作:是对申请到的内存,也就是类 A 的实例对象,进行初始化。没错,就是调用类 A 的构造函数至于 delete 操作,则正好相反:先调用析构函数,然后再释放内存。

3.无论是:malloc 和 new,它们都是可以被重载的。特别是开发操作系统和嵌入式系统时,往往没有可以直接使用的默认函数,开发者需要根据硬件配置和具体需要,重写合适的内存分配函数。

最后,默认情况下,系统提供的 malloc 和 new 都会从“堆”上申请内存。但如果自己重载了 malloc 和 new,那到底从哪里申请内存,就全靠自己把握了

05

热点问题

Q1:malloc/new operator 函数,是谁提供的?

A1:一般来说,是有库函数提供的,不过在执行的时候,需要操作系统支持,函数库与操作系统的接口是系统调用,具体细节,可以参考《CPU眼里:系统调用》

Q2:free 函数,没有传递:需要释放的内存空间大小,那它怎么知道:要释放多少内存呢?

A2:简单的说:在 malloc 申请内存块时,会多申请一点,用于存放内存块的大小。例如,要申请 8 字节的内存块时,就申请 12(8 + 4) 字节的内存块,其中前 4 个字节用于存放:内存块的真实长度,只把后 8 个字节返回给用户。

这样在 free 的时候,只需要往前查看4个字节,就知道需要释放多少内存空间了。

05

更系统、完整的学习

更加系统、全面、深入的学习C/C++知识,还可以参考阿布编写的,并被多位微软大佬联袂推荐的书籍:《CPU眼里的C/C++》

标签: #开机new cpu