garbage-collection - 如果对象的引用被置为null垃圾收集器是否会立即释放对象占用的内存 - 强引用置为null会不会被回收




D编程没有垃圾收集器 (4)

D的GC不像其他Java那样复杂。 它是开源的,所以任何人都可以尝试改进它。

有一个名为CDGC的实验性并发GC,目前有一个GSoC项目用于删除全局锁: http : //www.google-melange.com/gsoc/project/google/gsoc2012/avtuunainen/17001

确保使用LDC或GDC进行编译以获得更好的优化代码。

XomB项目也使用自定义运行时,但它是我认为的D版本1。 http://wiki.xomb.org/index.php?title=Main_Page

我今天一直在看D,表面上看起来相当惊人。 我喜欢它如何在语言中直接包含许多更高层次的构造,所以不必使用愚蠢的黑客或简洁的方法。 有一件事真的让我担心,如果GC。 我知道这是一个很大的问题,并且已经阅读了很多关于它的讨论。

我自己从这个问题萌生的简单测试表明GC非常慢。 比直接C ++做同样的事情要慢10倍以上。 (显然,测试并不直接转化为现实世界,但是性能打击是极端的,会减缓真实世界发生的类似行为(快速分配许多小对象)

我正在研究编写一个实时低延迟音频应用程序,GC可能会破坏应用程序的性能,使其几乎无用。 从某种意义上讲,如果它有任何问题,将会毁掉实时音频方面,因为与图形不同,音频以更高的帧速率(44000+ vs 30-60)运行。 (由于它的低延迟比标准的可以缓冲大量数据的音频播放器更重要)

禁用GC可将结果提高到C ++代码的20%左右。 这很重要。 我会在最后给出代码进行分析。

我的问题是:

  1. 用一个标准的智能指针实现代替D的GC是多么的困难,以至于依赖于GC的库仍然可以被使用。 如果我彻底删除GC,那么我将失去很多烦琐的工作,因为与C ++相比,D已经有了限制库。
  2. GC.Disable是否只暂时停止垃圾回收(阻止GC线程运行),GC.Enable会在停止的地方回收垃圾回收。 所以我可能会禁用GC在高cpu使用时间运行,以防止延迟问题。
  3. 有什么办法强制一个模式,不要一直使用GC。 (这是因为我没有在D编程,当我开始写我的眼镜不使用GC我想确保我不会忘记执行自己的清理。
  4. 是否可以轻松更换D中的GC? (不是我想要的,但有一天玩不同的GC方法可能很有趣...这与我想的类似)

我想要做的是交易记忆的速度。 我不需要GC每隔几秒就运行一次。 事实上,如果我可以正确地实现自己的数据结构的内存管理,那么根本就不需要经常运行。 只有当内存稀少时,我才需要运行它。 从我读过的东西看,尽管如此,你等待的时间越长,它就越慢。 由于在我的应用程序中通常会有一些时间,我可以不经问题就调用它,这将有助于缓解一些压力(但是再次,可能会有几个小时我将无法调用它)。

我并不担心内存限制。 我宁愿在速度上“浪费”内存(当然,最多也是一个点)。 首要的是延迟问题。

从我读过的内容来看,只要我不使用任何依赖GC的库或语言结构,我至少可以走C / C ++的路线。 问题是,我不知道那些做的。 我已经看到字符串,新的等提到,但这是否意味着我不能使用字符串的构建,如果我不启用GC?

我读过一些错误报告,说GC可能是错误的,这可以解释它的性能问题?

此外,D使用了更多的内存,事实上,D在C ++程序之前耗尽内存。 在这种情况下,我想大概是15%左右。 我想这是给GC的。

我意识到下面的代码并不代表你的平均程序,但是它说的是,当程序实例化很多对象时(比如在启动时),它们会慢得多(10倍是一个很大的因素)。 GC可以在启动时“暂停”,那么它不一定是个问题。

真正好的是,如果我能以某种方式让编译器自动GC一个本地对象,如果我没有具体释放它。 这几乎是两全其美。

例如,

{
    Foo f = new Foo();
    ....
    dispose f; // Causes f to be disposed of immediately and treats f outside the GC
               // If left out then f is passed to the GC.
               // I suppose this might actually end up creating two kinds of Foo 
               // behind the scenes. 

    Foo g = new manualGC!Foo();   // Maybe something like this will keep GC's hands off 
                                  // g and allow it to be manually disposed of.
}

事实上,实际上可以将不同类型的GC与不同类型的数据关联起来,而每个GC都是完全独立的。 这样我可以根据我的类型调整GC的性能。

码:

module main;
import std.stdio, std.conv, core.memory;
import core.stdc.time;

class Foo{
    int x;
    this(int _x){x=_x;}
}

void main(string args[]) 
{

    clock_t start, end;
    double cpu_time_used;


    //GC.disable();
    start = clock();

    //int n = to!int(args[1]);
    int n = 10000000;
    Foo[] m = new Foo[n];

    foreach(i; 0..n)
    //for(int i = 0; i<n; i++)
    {
        m[i] = new Foo(i);
    }

    end = clock();
    cpu_time_used = (end - start);
    cpu_time_used = cpu_time_used / 1000.0;
    writeln(cpu_time_used);
    getchar();
}

C ++代码

#include <cstdlib>
#include <iostream>
#include <time.h>
#include <math.h>
#include <stdio.h>

using namespace std;
class Foo{
public:
    int x;
    Foo(int _x);

};

Foo::Foo(int _x){
    x = _x;
}

int main(int argc, char** argv) {

    int n = 120000000;
    clock_t start, end;
    double cpu_time_used;




    start = clock();

    Foo** gx = new Foo*[n];
    for(int i=0;i<n;i++){
        gx[i] = new Foo(i);
    }


    end = clock();
    cpu_time_used = (end - start);
    cpu_time_used = cpu_time_used / 1000.0;
    cout << cpu_time_used;

    std::cin.get();
    return 0;
}

我建议你阅读这篇文章:http: //3d.benjamin-thaut.de/?p=20在那里你会发现一个标准库的版本,自己的内存管理,并完全避免垃圾收集。


您也可以只分配所有需要的内存块,然后使用内存池来获取没有GC的块。

顺便说一下,这并不像你提到的那么慢。 而GC.disable()并没有真正禁用它。


由于这还没有被关闭,所以最近版本的D有std.container库,它包含一个Array数据结构,与内置数组相比,它的内存效率更高。 我无法确认库中的其他数据结构是否也是有效的,但是如果您需要更多地关注内存,而不必诉诸手动创建不需要垃圾回收的数据结构,则可能值得考虑。





d