我想知道对运营商delete
的调用是否同步。换句话说,如果我这样做:
delete p;
C ++标准是否保证只有在此调用完成执行后才释放内存?或者是调用是异步的,并且只要它决定最好的时间,它就会安排OS的任务释放这个内存吗?
如果第一种情况是有效的,那么这是否意味着我们必须实现自己的异步删除工具?我问,因为我会说大多数时候我们(程序员)不关心内存是否完全释放,因此我们不希望我们的代码冻结并等待这个(最有可能是昂贵的?)系统调用完成,而是安排删除任务并立即继续执行。 C ++是否提供任何标准工具(可能通过标准库?)来完成这项工作而不重新发明轮子?
答案 0 :(得分:18)
delete
是同步的。现在,这并不意味着操作系统当时实际释放了底层内存,但从C ++系统的角度来看,它的行为就好像。
我在问,因为我会说大部分时间我们(程序员)都不关心内存是否正确释放
但是delete
并不主要是关于内存,它同样以确定的方式调用析构函数 - 它是一种通用的资源释放机制,不仅限于内存。在这里, 对于具有同步性非常重要,否则C ++的核心方面之一 - RAII - 将无效。
答案 1 :(得分:7)
无法保证delete p;
将内存释放回操作系统。事实上,在很多(大多数?)实现中,它不会做任何类似的事情。
当你调用delete
时, 的确发生了多少 - 在某些情况下它几乎是即时的(只是将块链接到空闲内存块列表)。在其他情况下,它确实做了更多的工作:销毁对象,并且可能搜索当前空闲列表中的相邻块,这些块可以与被释放的块合并。
答案 2 :(得分:4)
就你而言,一切都与你期望的完全一致,并且没有隐藏的陷阱或陷阱。你总是可以说T * p = new T; delete p;
这是正确的,无论这种情况发生在什么情况下。
鉴于操作系统通常必须同时为各种进程和线程分配内存,您可以认为该问题已经正确解决。
更正式地说,18.6.1.4/1(“数据竞赛”)说:
为了确定数据争用的存在,
operator new
的库版本,全局operator new
的用户替换版本以及C标准库函数calloc
和{{1} }就像它们只访问和修改返回值引用的存储一样。图书馆版本malloc
,operator delete
的用户替换版本以及C标准库函数operator delete
的行为应该只是访问和修改其第一个参数引用的存储。
关于“阻塞性”:这一切都归结为C库的分配功能。除了“此函数返回指向某个内存的指针”之外,没有指定任何内容。它取决于平台如何提供内存分配。
答案 3 :(得分:0)
无论如何,C / C ++中的免费调用已经非常快。 在这方面,没有理由推迟删除它以获得更合适的时间。 任何保留你需要为此目的做的书都会抵消实际的免费通话时间。
如果你的析构函数做了更多的工作,比如关闭数据库连接的套接字那么你可以在以后做这种类型的工作,但这应该是一个例外情况。