-1

我目前正在将 Boehm 垃圾收集器用于 C++ 中的大型应用程序。虽然它有效,但在我看来,GC 对我的目的来说太过分了(我不喜欢将此作为依赖项,我必须不断地考虑并在我所做的一切中考虑 GC,以免踩到它的脚趾)。我想找到一个更适合我需求的更好的解决方案,而不是碰巧涵盖它的一揽子解决方案。

在我的情况下,我有一个想要“收集”的特定类(以及从该类继承的所有内容)。我不需要一般的垃圾收集,在除了这个特定的类之外的所有情况下,我都可以轻松地管理我自己的内存。

在我开始使用 GC 之前,我使用了引用计数,但是引用循环和频繁的更新使得这不是一个理想的解决方案。

我有更好的方法来跟踪这门课吗?一种不涉及额外的库依赖项,如 boost。

编辑: 最好简要说明我的对象的潜在寿命。

一个函数创建我的类的一个新实例,并且可能(或可能不)使用它。无论如何,它将这个新实例作为返回值传回给调用者。调用者也可能(或可能不)使用它,并且再次将它传递回堆栈,最终到达顶层函数,该函数只是让指针逐渐消失。

我不能只删除顶层的指针,因为“可能使用”的一部分涉及将指针传递给其他函数,这些函数可能(或可能不)存储指针以供将来在其他地方使用。

我希望这能更好地说明我要解决的问题。我目前使用 Boehm 垃圾收集器解决它,但如果可能的话,我想要更简单、不涉及依赖的解决方案。

4

3 回答 3

1

在嵌入式系统世界或对实时事件至关重要的程序中,垃圾收集是不受欢迎的。使用动态内存的点不好。

使用动态内存分配,会发生碎片。垃圾收集器用于定期安排内存以减少碎片,例如组合顺序释放的块。主要问题是何时执行此碎片整理或运行 GC。

一些建议的替代方案:

重新设计您的系统以避免动态内存分配。
分配静态缓冲区并使用它们。例如,在 RTOS 系统中,为消息预先分配空间,而不是动态分配它们。

使用堆栈,而不是堆。 如果可能,将堆栈用于动态分配的变量。如果变量需要超出函数执行的生命周期,这不是一个好主意。

限制可变大小的数据。
与静态缓冲区一起,对可变长度数据或未知大小的传入数据进行限制。这可能意味着当输入无法停止时,必须暂停传入数据或进行多次缓冲。

创建自己的内存分配器。
创建许多分配不同大小块的内存池。这将减少碎片。例如,对于小块,也许bitset可以使用 a 来确定哪些字节正在使用以及哪些可用。也许需要另一个 64 字节块的池。一切都取决于您系统的需求。

于 2013-11-10T19:09:24.033 回答
0

有了记忆,您应该始终尝试并拥有清晰的所有权和对生命的了解。生命周期决定了您从哪里获取内存(与其他因素一样),即用于作用域的堆栈、用于重用的池等。所有权将告诉您何时以及是否释放内存。在您的情况下,GC 拥有所有权并决定何时释放。通过引用计数,包装类执行此逻辑。如果使用手动内存管理,不明确的所有权会导致难以维护代码。您必须避免使用后释放、双重释放和内存泄漏。

要解决您的问题,请弄清楚谁应该保留所有权。这将决定要使用的算法。GC 和 ref 计数是流行的选择,但有很多。如果所有权不明确,请将其交给负责跟踪它的第 3 方。如果所有权是共享的,请确保所有各方都知道它,也许通过专门的类来执行它。这也可以通过简单的约定来强制执行,即 foo 类型的对象不应该在内部保留 bar 类型的 ptrs,因为它们不拥有它们,如果它们拥有它们,它们就不能假定它们总是有效的,并且可能必须首先检查其有效性。等等。

如果您发现这很难确定,则可能表明代码非常复杂。可以用更简单的方式制作吗?

了解如何使用和访问内存是编写干净代码以进行维护和性能优化的关键。无论使用何种语言都是如此。

祝你好运。

于 2013-11-13T04:16:57.480 回答
0

如果您真的只需要对与单个类关联的内存分配进行特殊处理,那么您应该考虑为该类重载 new 运算符。

class MyClass
{
public:
  void *operator new(size_t);
  void operator delete(void *);
}

你可以实现这些操作符来做任何你需要跟踪内存的事情:从一个特殊的池中分配它,将引用放在一个链表上进行跟踪,等等。

void* MyClass::operator new(size_t size)
{
    void *p = my_allocator(size);  // e.g., instead of malloc()
    // place p on a linked list, etc.
    return p;
}

void MyClass::operator delete(void *p)
{
    // remove p from list...
    my_free(p);
}

然后,您可以编写可以遍历您保留的列表的外部代码,以检查每个当前分配的 MyClass 实例,并根据您的情况进行 GC 处理。

于 2013-11-10T19:46:25.060 回答