D垃圾收集器有效吗?

Meh*_*dad 4 garbage-collection d

所以我尝试通过在Windows上运行该程序来测试D垃圾收集器是否正常工作.

DMD 2.057和2.058测试都给予同样的结果,不管是不是我指定-release,-inline,-O,等.

代码:

import core.memory, std.stdio;

extern(Windows) int GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);

struct MEMORYSTATUSEX
{
    uint Length, MemoryLoad;
    ulong TotalPhys, AvailPhys, TotalPageFile, AvailPageFile;
    ulong TotalVirtual, AvailVirtual, AvailExtendedVirtual;
}

void testA(size_t count)
{
    size_t[] a;
    foreach (i; 0 .. count)
        a ~= i;
    //delete a;
}

void main()
{
    MEMORYSTATUSEX ms;
    ms.Length = ms.sizeof;

    foreach (i; 0 .. 32)
    {
        testA(16 << 20);
        GlobalMemoryStatusEx(ms);
        stderr.writefln("AvailPhys: %s MiB", ms.AvailPhys >>> 20);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

AvailPhys: 3711 MiB
AvailPhys: 3365 MiB
AvailPhys: 3061 MiB
AvailPhys: 2747 MiB
AvailPhys: 2458 MiB
core.exception.OutOfMemoryError
Run Code Online (Sandbox Code Playgroud)

当我取消注释delete a;语句时,输出是

AvailPhys: 3714 MiB
AvailPhys: 3702 MiB
AvailPhys: 3701 MiB
AvailPhys: 3702 MiB
AvailPhys: 3702 MiB
...
Run Code Online (Sandbox Code Playgroud)

所以我想问题很明显...... GC真的有用吗?

dsi*_*cha 8

这里的问题是错误的指针.D的垃圾收集器是保守的,这意味着它并不总是知道什么是指针而什么不是.它有时必须假设指向GC分配的内存(如果被解释为指针)的位模式是指针.这对于大型分配来说​​主要是一个问题,因为大块是错误指针的更大目标.

你每次打电话都要分配大约48 MB testA().根据我的经验,这足以几乎保证在32位系统上会有一个错误的指针进入块.如果您以64位模式编译代码(在Linux,OSX和FreeBSD上支持但在Windows上不支持),您可能会得到更好的结果,因为64位地址空间更加稀疏.

至于我的GC优化(我是Cyber​​Shadow提到的David Simcha),有两批.一个人已经服用超过6个月,并没有造成任何问题.另一个仍在审查作为拉取请求,并且还没有在主要的druntime树中.这些可能不是问题.

短期来说,解决方案是手动释放这些巨大的块.从长远来看,我们需要添加精确的扫描,至少对于堆来说.(精确的堆栈扫描是一个更难的问题.)几年前我写了一个补丁来做这个,但它被拒绝了,因为它依赖于模板和编译时间函数评估来生成每种数据类型的指针偏移信息.希望这些信息最终将由编译器直接生成,我可以为垃圾收集器重新创建精确的堆扫描补丁.