首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当调用delete[] X命令时,到底会发生什么?谁应该对此负责?

当调用delete[] X命令时,到底会发生什么?谁应该对此负责?
EN

Stack Overflow用户
提问于 2016-01-26 13:41:23
回答 5查看 121关注 0票数 0

我正在尝试找出谁是组件或模块(可能属于操作系统?)这实际上是在应用程序或进程运行时执行的操作,特别是运行命令delete[] X

我的问题是在我读到关于delete[] X的文章后提出的,我知道编译器有责任(根据它的实现)知道要删除多少X对象。但是,编译器在运行时并不是“活动的”!我的意思是,在编译时,编译器不知道用户在新命令中需要多少内存,在删除时也不知道,那么当程序实际运行时,在运行时到底发生了什么?

我读到的答案之一是所谓的运行时系统,它是什么?它是否连接到CPU -因为CPU最终会执行命令...或者是操作系统?

我看到的另一个答案是“由系统的分配器完成的”(How does delete[] know how much memory to delete?) --再说一次,这个组件(操作系统,CPU)在哪里?

EN

回答 5

Stack Overflow用户

发布于 2016-01-26 14:07:34

C++运行时(间接地)使用Operating System原语来更改运行程序的processvirtual address space

阅读有关computer architectureCPU modesoperating systemsOS kernelssystem callsinstruction setsmachine codeobject codelinkers、<代码>C12、<代码>C13、<代码>C14、<代码>C15的更多信息。

在我的Linux系统上,new (由C++标准库提供)通常构建在malloc(3) (由C标准库提供)之上,它可以调用mmap(2)系统调用(在内核中实现),从而改变虚拟地址空间(通过处理MMU)。而delete (来自C++标准库)通常建立在free(3)之上,它可以调用munmap(2)系统调用来改变虚拟地址空间。

细节上的事情要复杂得多:

  • new在分配内存后调用构造函数malloc
  • delete在释放内存之前调用析构函数free
  • free通常将释放的内存区标记为可供将来的malloc重用(因此通常不使用munmap)
  • so释放内存malloc通常在向内核
  • 请求更多地址空间(使用mmap)之前重用先前释放的内存区)用于数组
  • delete[],内存区包含数组的大小,当您编写代码时,在loop
  • technically,中调用构造函数(new[])或析构函数(delete[])首先使用SomeClass*p = new SomeClass(12); (它调用malloc)分配内存,然后使用12作为您的代码delete p;调用::operator new的构造函数,调用SomeClass的析构函数,然后使用::operator delete (它调用<代码>D57)<代码>H258<代码>F259释放内存。

顺便说一句,Linux系统是由free software组成的,所以我强烈建议您在您的机器上安装一些Linux发行版并使用它。因此,您可以研究内核的libstdc++ (标准C++库,它是GCC编译器源代码的一部分,但通过您的程序链接)、libc (标准C库)的源代码。您还可以strace(1)您的C++程序和进程,以了解它正在做什么system calls

如果使用GCC,您可以通过使用g++ -Wall -O -fverbose-asm -S foo.cc编译foo.cc C++源文件来获得生成的汇编程序代码,这会生成foo.s汇编程序文件。您还可以使用g++ -Wall -O -fdump-tree-gimple -c foo.cc在编译器中获得中间 internal representation的一些文本视图(您将获得一些foo.cc.*.gimple,也许还有许多其他的GCC转储文件)。您甚至可以使用GCC MELT工具(我设计并实现了它的大部分;use g++ -fplugin=melt -fplugin-arg-melt-mode=findgimple)来搜索Gimple表示内部的内容。

标准C++库具有内部不变量和约定,C++编译器负责在发出汇编代码时遵循它们。因此,编译器和它的标准C++库是紧密协作地共同设计和编写的(您的C++库实现中的一些肮脏技巧需要编译器支持,可能是通过编译器内置等等)。这并不是C++所特有的: Ocaml团队还共同设计并共同实现了Ocaml语言及其标准库。

C++运行时系统在概念上有几层: C++标准库libstdc++、C标准库libc、操作系统(以及最底层的硬件,包括内存管理单元)。所有这些都是实现细节,C++11语言标准并没有真正提到它们。

票数 2
EN

Stack Overflow用户

发布于 2016-01-26 14:10:16

编译器负责生成代码,以便在需要时对其进行delete。当它发生时,它不需要运行。生成的代码可能是对执行以下操作的例程的函数调用:

代码语言:javascript
运行
复制
void delete_arr(object *ptr)
{
    size_t *actual_start = ((size_t *)ptr) - 1;
    int count = *actual_start;

    for (int i = count-1; i >= 0; i--)
        destruct(ptr[i]);

    free(actual_start);
}

当调用new[]时,它实际上保存了分配的内存旁边的元素数量。当您调用delete[]时,它会查找计数,然后删除该数量的元素。

提供这些功能的库称为C++标准库或C++运行时环境。该标准没有说明运行时的组成,因此定义可能会有所不同,但要点是它需要支持运行C++代码。

票数 2
EN

Stack Overflow用户

发布于 2016-01-26 14:11:33

可能是helpfull

对于每次调用::运算符

  • (),它将采用传递的对象大小并添加额外数据的大小
  • 将分配上一步推导出的大小的内存块
  • 它将偏移指向未被额外数据占用的块的部分的指针,并将该偏移值返回给调用方

运算符delete()将在反向移位指针、访问额外数据、释放内存时执行相同的操作。

通常在删除分配到堆中的对象数组时使用delete []。据我所知,new []还会在分配的内存开始处添加额外的数据,在内存中为delete []操作符存储有关数组大小的信息。也可以是useful

换句话说,在一般情况下,由new[]分配的内存块在实际数据前面有两组额外的字节:以字节为单位的块大小(由

引入)和元素计数(由new[]引入)。第二个是可选的,如您的示例所示。第一个通常总是存在的,因为它是由malloc无条件分配的。也就是说,即使你只请求20个字节,你的malloc调用也会实际分配超过20个字节。这些额外的字节将被malloc用来存储以字节为单位的块大小。..。

正如您所相信的那样,new[]从操作符new[]请求的“额外字节”并不用于“存储已分配内存的大小”。它们用于存储数组中元素的数量,以便delete[]知道要调用多少析构函数。在你的例子中,析构函数是微不足道的。没必要打电话给他们。因此,不需要分配这些额外的字节并存储元素计数。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35007655

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档