我们为什么要删除new分配的内存?

时间:2017-04-29 09:09:11

标签: c++ garbage-collection

据说new分配的内存应该由delete释放,但现代桌面操作系统会回收内存,即使你没有delete它。那么我们为什么要delete分配新的内存?

同样assert被称为不调用析构函数,似乎它在STL中被广泛使用(至少VS2015就是这样)。如果建议deletenew分配的内存(stringmapvector等类使用析构函数删除分配的内存),为什么开发人员仍然使用大量assert呢?

5 个答案:

答案 0 :(得分:1)

  

据说new分配的内存应该被释放   delete,但现代桌面操作系统将回收内存   你不要delete它。那么我们为什么要delete分配内存呢?   按new

小心!在程序完成后,操作系统仅回收内存。这是,就像Java或C#中的垃圾收集一样,它在程序运行时释放内存

如果您不是delete(或者更确切地说,如果您不确保资源管理类调用delete,例如std::unique_ptr,{ {1}}或std::string),然后内存使用量将继续增长,直到内存不足为止。

更不用说析构函数不会运行,如果你有类型的对象,其析构函数不仅仅是释放内存,那么这很重要。

  

同样std::vector被称为不调用析构函数,

更确切地说,assert导致程序以不调用析构函数的方式终止,除非相应的转换单元是在定义了assert预处理器宏的情况下编译的,在这种情况下{{1什么也没做。

  似乎它在STL中被广泛使用(至少VS2015会这样做)。

是的,Visual C ++ 2015的标准库实现做了很多。您还应该在自己的代码中自由使用它来检测错误。

C ++标准本身没有规定如何以及NDEBUG应该出现在标准库函数的实现中。它确实指定了程序行为未定义的情况;那些通常对应于库实现中的assert(这是有意义的,因为如果行为是未定义的,那么实现可以自由地执行任何,那么为什么不使用那个自由呢?一种有用的方法来检测错误?)。

  

如果建议assertassert分配的内存(类似于   deletenewstring使用析构函数删除已分配的   内存),为什么开发人员仍然使用大量map呢?

因为如果断言失败,那么希望您的程序立即终止,因为您已检测到错误。如果您检测到错误,那么您的程序根据定义处于未知状态。允许程序通过运行析构函数继续处于未知状态可能很危险,并可能危及系统完整性和数据一致性。

毕竟,正如我上面所说,析构函数不仅可以调用vector几次。析构函数关闭文件,刷新缓冲区,写入日志,关闭网络连接,清除屏幕,连接线程或提交或回滚数据库事务。析构函数可以执行许多可以修改并可能损坏系统资源的事情。

答案 1 :(得分:1)

  

我们为什么要删除new分配的内存?

因为否则

  1. 内存泄露。对于长时间运行的软件(如服务器和守护进程)来说,不泄漏内存绝对是至关重要的,因为泄漏会累积并占用所有可用内存。

  2. 不会调用对象的析构函数。程序的逻辑可能取决于被调用的析构函数。不调用某些析构函数也可能导致非内存资源泄露。

  3.   

    断言也称为不调用析构函数

    失败的断言会终止整个过程,因此程序的逻辑是否保持一致,内存或其他资源是否泄露并不重要,因为过程不会重复使用这些资源。 / p>

      

    似乎它在STL中被广泛使用(至少VS2015会这样做)

    准确地说,我不认为标准库被指定使用断言宏。它可以使用它的唯一情况是你有未定义的行为。如果你有UB,那么泄露的记忆是你最不担心的。

    如果您知道对象的析构函数是微不足道的,并且您知道该对象在整个程序中使用(因此,它本质上是一个单例),那么故意泄漏对象是非常安全的。这确实有一个缺点,它可能会被内存泄漏消毒器检测到,您可能希望用它来检测意外的内存泄漏。

答案 2 :(得分:1)

应用程序 - 在执行过程中 - 动态创建在整个程序执行过程中不会使用的对象,这是一种常见模式。如果应用程序创建了许多临时生命周期的对象,那么它必须以某种方式管理内存以便不会耗尽它。请注意,内存仍然有限,因为操作系统通常不会将所有可用内存分配给应用程序。操作系统,特别是那些驱动有限设备(如移动电话)的操作系统,一旦产生过高的内存压力,甚至可能会杀死应用程序。

因此,您应该释放那些不再使用的对象的内存。 C ++提供storage class specifiers使这种处理更容易。默认情况下,automatic storage duration删除对象,一旦它们超出范围(即它们的封闭块,例如定义它们的函数,就完成)。 static个对象一直保留到正常程序执行结束(如果到达),并且动态分配的对象保持不变,直到您调用delete

请注意 - 在任何情况下 - 任何对象都将在程序执行结束后继续存在,因为操作系统将释放整个应用程序内存。对于正常的程序终止,将调用static个对象的析构函数(但不能用于之前未删除的动态创建对象的对象)。对于异常程序终止,例如由assertexit或操作系统触发,不会调用析构函数;你可以考虑一个程序终止,因为你关闭了电源。

答案 3 :(得分:0)

如果您不删除您引入了内存泄漏。每次调用此运算符时,该进程都会浪费其地址空间的一部分,直到它最终耗尽内存。

答案 4 :(得分:0)

你的程序完成后你不需要关心内存泄漏,所以原则上这没关系:

int main(){
    int* x = new int(1);
}

然而,这并不是人们通常如何使用记忆。通常你需要为你只使用很短时间的内容分配内存,然后你想要在你不再需要时释放内存。考虑这个例子:

int main(){
    while ( someCondition ) {
        Foo* x = new Foo();
        doSomething(*x);
    }  // <- already here we do not need x anymore
}     

该代码将为x累积越来越多的内存,即使所有使用的内容都是x的单个实例。这就是为什么一个人应该在需要的范围结束时释放最新的内存(一旦你离开了范围,你就无法释放它!)。因为忘记delete并不好,所以应尽可能使用RAII:

int main(){
    while ( someCondition ) {
        Foo x;
        doSomething(x);
    }  // <- memory for x is freed automatically
}