现在哪些生态系统允许创建多个堆?
一个明显的答案是“C++”(如果您不认为一种语言本身是一个“生态系统”,请随意填写周围的部分)。
C++ 允许您沿几个不同的轴指定堆。一种是按对象的类型——你可以通过重载operator new 和operator delete 来为特定类型指定分配:
class Foo {
static void *operator new(size_t size);
static void operator delete(void *block, size_t size);
};
然后由您将这些堆管理功能连接到实际的内存源。您可以通过::operator new 分配它,或者您可以(例如)直接进入操作系统,例如在Windows 上使用GlobalAlloc 或VirtualAlloc,在类UNIX 系统上使用sbrk,或者只使用pre - 裸机嵌入式系统上的指定内存块。
沿着稍微不同的轴,C++ 标准库中的所有容器都通过分配器类分配和释放内存。任何特定集合的分配器都被指定为模板参数,因此(例如)std::vector 的声明看起来像这样:
template <class T, class Alloc=std::allocator<T>>
class vector {
// ...
};
这使您可以指定一个堆,用于在该集合中分配对象。就像operator new 和operator delete 一样,这实际上只指定了集合将分配和释放内存的接口——由您将其连接到实际管理堆的代码。
垃圾回收
就垃圾收集而言:我个人觉得它很烦人,并建议不要将其用作一般规则。问题是它虽然可以(至少从一个角度)解决某些类型的内存管理问题,但它对其他资源的管理没有任何帮助——而且(不幸的是)我还没有看到像跟踪收集器这样的东西文件句柄、网络套接字、数据库连接等等。 RAII 提供了一个统一的方法来处理一般的资源管理。
也就是说,如果你真的坚持使用 GC,C++ 也确实支持。在 C++11 之前,GC 在实际层面上完全可用,但在一些晦涩的情况下会导致技术上未定义的行为,例如:
- 将指针存储在文件中,然后将其读回,或者
- 修改指针的位,然后撤消该修改
...然后获取重新构成的指针并取消引用它。显然,虽然指针对 CPU 不可见,但指向的内存块变得符合 GC 条件,因此后来的取消引用引起了问题。 C++11 定义了这些情况,并添加了一些库调用(例如,declare_reachable、undeclare_reachable)来处理它们(例如,如果您调用decalare_reachable(block);,那么block 不符合收集条件,无论如何指向它的指针是否可见)。因此,如果您想将 GC 与 C++ 一起使用,您可以,并且已彻底指定定义行为的界限。唯一的问题是,基本上没有代码调用过declare_reachable 和/或undeclare_reachable,因此在实际使用中它们可能几乎没有帮助(但指针调配和/或文件中的存储非常罕见,以至于这不太可能造成真正的问题)。
对于一个实际示例,您可能需要查看Boehm-Demers-Weiser collector(如果您还没有的话)。