18

我想知道对运营商的调用是否delete是同步的。换句话说,如果我这样做:

delete p;

C++ 标准是否保证只有在此调用完成执行后才会释放内存?或者调用是异步的并且只是为操作系统安排一个任务来释放这个内存,一旦它决定这是最好的时间?

如果第一种情况是有效的,那么这是否意味着我们必须实现自己的异步删除器工具?我问是因为我会说大多数时候我们(程序员)并不关心内存何时被准确释放,因此我们不希望我们的代码冻结并等待这个(很可能很昂贵?)系统调用完成,而是安排删除任务并立即继续执行。C++ 是否提供任何标准工具(可能通过标准库?)来做到这一点而无需重新发明轮子?

4

4 回答 4

18

delete是同步的。现在,这并不意味着底层内存实际上在那个时候被操作系统释放了,而是从 C++ 系统的角度来看,它的行为就像。

我问是因为我会说大多数时候我们(程序员)并不关心内存何时被完全释放

delete主要不是关于内存,它与以确定性方式调用析构函数同样重要——它是一种通用的资源释放机制,不限于内存。在这里,具有同步性很重要,否则 C++ 的核心方面之一——RAII——将无法工作。

于 2013-04-15T20:40:46.950 回答
7

没有什么能保证delete p;将内存释放回操作系统 - 永远。事实上,在相当多的(大多数?)实现中,它不会做任何事情。

但是,调用时发生的确切情况delete会有所不同——在某些情况下,它几乎是即时的(只需将块链接到可用内存块的列表)。在其他情况下,它会做更多的工作:销毁对象,并可能在当前空闲列表中搜索可以与被释放的块合并的相邻块。

于 2013-04-15T20:42:39.563 回答
4

就您而言,一切都按照您的预期进行,没有隐藏的陷阱或陷阱。T * p = new T; delete p;无论发生在什么情况下,您都可以说这是正确的。

鉴于操作系统通常必须同时为各种进程和线程分配内存,您可以假设该问题已得到正确解决。

更正式地说,18.6.1.4/1(“数据竞赛”)说:

为了确定数据竞争的存在, 的库版本operator new、 global 的用户替换版本operator new和 C 标准库函数的calloc行为malloc应该就像它们只访问和修改返回值引用的存储一样。的库版本operator delete、用户替换版本operator delete和 C 标准库函数的free行为就像它们只访问和修改了它们的第一个参数引用的存储一样。

关于“阻塞性”:这一切都归结为 C 库的分配函数的作用。除了“此函数返回指向某个内存的指针”之外,没有指定任何内容。它如何提供内存分配取决于平台。

于 2013-04-15T20:37:24.537 回答
0

无论如何,C/C++ 中的免费调用已经非常快了。在这方面,您没有理由延迟删除它,以便在更合适的时间进行。为此目的,您需要做的任何簿记都将抵消实际的免费通话时间。

如果你的析构函数做更多的工作,比如关闭数据库连接的套接字,那么你可以在以后做这种类型的工作,但这应该是一个例外情况。

于 2013-04-15T20:42:22.867 回答