gpt4 book ai didi

garbage-collection - 没有垃圾收集器的 D 编程

转载 作者:行者123 更新时间:2023-12-03 07:20:10 25 4
gpt4 key购买 nike

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

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

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

禁用 GC 将结果改进到 C++ 代码的 20% 以内。这很重要。我会在最后给出代码以供分析。

我的问题是:

  • 用标准的智能指针实现替换 D 的 GC 以便仍然可以使用依赖于 GC 的库是多么困难。如果我完全删除 GC,我将失去很多繁重的工作,因为与 C++ 相比,D 已经具有有限的库。
  • GC.Disable 是否只是暂时停止垃圾收集(防止 GC 线程运行),而 GC.Enable 会从停止的地方恢复。因此,我可能会禁用 GC 在 CPU 使用率高的时刻运行,以防止出现延迟问题。
  • 有什么方法可以强制模式不始终如一地使用 GC。 (这是因为我没有用 D 编程,当我开始编写不使用 GC 的眼镜时,我想确保我不会忘记实现自己的清理。
  • 是否可以轻松更换 D 中的 GC? (不是我想要,但有一天尝试使用不同的 GC 方法可能会很有趣……这与我想的 1 类似)

  • 我想做的是用内存换取速度。我不需要每隔几秒钟运行一次 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;
    }

    最佳答案

  • D 几乎可以使用任何 C 库,只需定义所需的函数即可。 D 也可以使用 C++ 库,但 D 不理解某些 C++ 构造。所以... D 可以使用几乎与 C++ 一样多的库。它们只是不是本地 D 库。
  • 来自 D 的图书馆引用资料。
    核心内存:

    static nothrow void disable();

    Disables automatic garbage collections performed to minimize the process footprint. Collections may continue to occur in instances where the implementation deems necessary for correct program behavior, such as during an out of memory condition. This function is reentrant, but enable must be called once for each call to disable.

    static pure nothrow void free(void* p);

    Deallocates the memory referenced by p. If p is null, no action occurs. If p references memory not originally allocated by this garbage collector, or if it points to the interior of a memory block, no action will be taken. The block will not be finalized regardless of whether the FINALIZE attribute is set. If finalization is desired, use delete instead.

    static pure nothrow void* malloc(size_t sz, uint ba = 0);

    Requests an aligned block of managed memory from the garbage collector. This memory may be deleted at will with a call to free, or it may be discarded and cleaned up automatically during a collection run. If allocation fails, this function will call onOutOfMemory which is expected to throw an OutOfMemoryError.



    所以是的。在此处阅读更多信息:http://dlang.org/garbage.html

    在这里:http://dlang.org/memory.html

    如果你真的需要类,看看这个:http://dlang.org/memory.html#newdelete
    delete 已被弃用,但我相信您仍然可以 free() 它。
  • 不要使用类,使用结构。结构是堆栈分配的,类是堆。除非你需要多态或其他类支持的东西,否则它们是你正在做的事情的开销。如果你愿意,你可以使用 malloc 和 free。
  • 或多或少...在这里填写函数定义:https://github.com/D-Programming-Language/druntime/blob/master/src/gcstub/gc.d .设置了一个 GC 代理系统以允许您自定义 GC。所以这并不是设计师不想让你做的事情。

  • 这里的小GC知识:
    垃圾收集器不能保证为所有未引用的对象运行析构函数。此外,没有指定垃圾收集器为未引用对象调用析构函数的顺序。这意味着当垃圾收集器为一个类的对象调用析构函数时,该对象的成员是对垃圾收集对象的引用,这些引用可能不再有效。这意味着析构函数不能引用子对象。此规则不适用于自动对象或使用 DeleteExpression 删除的对象,因为垃圾收集器未运行析构函数,这意味着所有引用都是有效的。

    导入 std.c.stdlib;那应该有 malloc 和 free。

    导入 core.memory;这有 GC.malloc, GC.free, GC.addroots,//向 GC 添加外部内存...

    字符串需要 GC,因为它们是不可变字符的动态数组。 ( immutable(char)[] ) 动态数组需要 GC,静态不需要。

    如果您想要手动管理,请继续。
    import std.c.stdlib;
    import core.memory;

    char* one = cast(char*) GC.malloc(char.sizeof * 8);.
    GC.free(one);//pardon me, I'm not used to manual memory management.
    //I am *asking* you to edit this to fix it, if it needs it.

    为什么要为 int 创建一个包装类?你所做的只是减慢速度和浪费内存。
    class Foo { int n; this(int _n){ n = _n; } }
    writeln(Foo.sizeof); //it's 8 bytes, btw
    writeln(int.sizeof); //Its *half* the size of Foo; 4 bytes.


    Foo[] m;// = new Foo[n]; //8 sec
    m.length=n; //7 sec minor optimization. at least on my machine.
    foreach(i; 0..n)
    m[i] = new Foo(i);


    int[] m;
    m.length=n; //nice formatting. and default initialized to 0
    //Ooops! forgot this...
    foreach(i; 0..n)
    m[i] = i;//.145 sec

    如果你真的需要,那么用 C 编写时间敏感函数,并从 D 调用它。
    哎呀,如果时间真的那么重要,请使用 D 的内联汇编来优化所有内容。

    关于garbage-collection - 没有垃圾收集器的 D 编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13574552/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com