【问题标题】:Boost shared_ptr does not destroy the object immediatelyBoost shared_ptr 不会立即销毁对象
【发布时间】:2013-01-22 09:24:33
【问题描述】:

我正在用 C++ 开发一个贝叶斯推理采样器,它在树上传递很多信息,而这棵树是在智能指针(Boost 的 shared_ptr 和 weak_ptr)的帮助下实现的。

在推理过程中(即运行一个较长的 C++ 函数 1-2 分钟),树发生了很大变化,创建和销毁了许多节点。

推理过程完全(100% 负载)占用处理器(一个线程,更准确地说)。由于某种原因,新内存(用于新节点)被占用,但旧内存没有被完全释放,这会在 1-2 分钟的推理后导致内存溢出。

不过,如果我在推理过程中添加暂停,似乎程序会完全破坏旧对象,并且一切正常。

在我看来,原因是析构函数(或者更准确地说,它之后发生的事情,即内存释放)由于某种原因被延迟了。

请告诉我: 1)这似乎是一个真正的问题? 2)如果是,最好等待“足够的内存”被释放?什么是标准策略?

(程序正在Unix上运行。)

【问题讨论】:

  • 对我来说,听起来您的 shared_ptr 仍然有对它们的引用,因此不会被直接销毁。但老实说,没有任何代码很难说。
  • shared_ptr 只是调用delete。您确定观察到的行为不是由于 delete 造成的吗?因为已知delete 实现会推迟实际解除操作,假设它们可以回收分配。
  • MSalters,您能否提供有关延迟释放的删除实现的参考信息?我认为这可能正是我的情况。 (对不起,还没找到自己。)
  • 你有没有试过在类析构函数中添加一个 printf 来记录它被调用的时候?这样你就知道它是否被破坏了。

标签: c++ boost destructor shared-ptr smart-pointers


【解决方案1】:

您观察到的内存问题似乎并不在于 C++ 本身。如果 shared_ptr 释放它的内存,它会立即释放它,而不是以某种延迟的方式。但是,您的操作系统可能会在它认为合适的时候延迟“真正的”发布一段时间。在像 Windows 的“任务管理器”这样的程序中,您的程序可能会消耗越来越多的内存,而这只是操作系统为您保留的内存,但您实际上并没有占用。如果您的计算产生如此繁重的处理器负载,调度程序可能会延迟相当“不重要”的任务(例如释放内存),直到有时间,以免妨碍您的计算等更重要的事情。

但是,释放和分配内存的成本很高。而且您似乎可以互换地释放和分配大量内存。您应该考虑通过自己的内存管理(如内存池等)或通过回收对象(即节点)本身来回收该内存,这意味着不是真正销毁它们,而是将它们归还给某个“节点池”并用新值重置它们。两者都可以与 shared_ptr 一起完成。

【讨论】:

  • 谢谢!请您告诉,如果不使用内存池概念,有没有办法(1)控制调度程序优先级以执行释放作为第一优先级,(2)或者如果不可能调整调度程序,如何合理并优雅地暂停以等待必要的释放?
【解决方案2】:

听起来你的树中有循环,即它使用shared_ptr 作为子指针和父指针,这可以防止自动树节点破坏。使用普通指针可能会更好。

【讨论】:

  • 或者在一个方向使用强指针,在另一个方向使用弱指针。或者在应该删除对象时手动切断指针。
  • @DavidSchwartz 虽然它不能比普通指针简单。
  • 不必跟踪何时可以安全地删除对象通常比必须跟踪更简单。使用我的两种方法,您都不必这样做。
  • 对不起,我使用的正是weak_ptr作为父母。似乎解除分配的问题更大,而不是 shared_ptr 的计数器。谢谢!
  • @DavidSchwartz 每次我看到一个初学者在树上使用智能指针时,他们的双腿都会被打掉。
【解决方案3】:

当最后一个指向对象的shared_ptr被销毁时,该对象立即被删除。所以你得到的听起来很奇怪。我能想到的唯一想法是您已将垃圾收集器附加到您的实现中......否则请仔细检查所有旧对象是否被销毁。

【讨论】:

    猜你喜欢
    • 2021-08-14
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    • 2017-05-23
    • 2023-02-08
    • 1970-01-01
    • 2019-12-30
    • 1970-01-01
    相关资源
    最近更新 更多