私は今日Dを見てきました、そして表面上それはかなり驚くべきように見えます。言語に直接多くの高レベルの構造が含まれているので、ばかげたハックや簡潔なメソッドを使用する必要がないのが好きです。GCの場合に本当に心配することが1つあります。私はこれが大きな問題であることを知っており、それについて多くの議論を読んだことがあります。
ここでの質問から生まれた私自身の簡単なテストは、GCが非常に遅いことを示しています。同じことを行うストレートC++よりも10倍以上遅くなります。(明らかに、テストは実際の世界に直接変換されませんが、パフォーマンスの低下は極端であり、同様に動作する現実の世界が遅くなります(多くの小さなオブジェクトをすばやく割り当てます)
リアルタイムの低遅延オーディオアプリケーションの作成を検討していますが、GCによってアプリケーションのパフォーマンスが低下し、ほとんど役に立たなくなる可能性があります。ある意味で、問題があると、リアルタイムのオーディオの側面が台無しになります。これは、グラフィックスとは異なり、オーディオがはるかに高いフレームレート(44000+対30-60)で実行されるため、はるかに重要です。(レイテンシーが低いため、大量のデータをバッファリングできる標準のオーディオプレーヤーよりも重要です)
GCを無効にすると、結果がC ++コードの約20%以内に改善されました。これは重要です。分析のために最後にコードを示します。
私の質問は次のとおりです。
- Gに依存するライブラリを引き続き使用できるように、DのGCを標準のスマートポインタ実装に置き換えることはどれほど難しいか。GCを完全に削除すると、DにはC ++と比較してすでに制限ライブラリがあるため、多くのうんざりする作業が失われます。
- GC.Disableは、ガベージコレクションを一時的に停止するだけで(GCスレッドが実行されないようにします)、GC.Enableは中断したところから再開します。そのため、レイテンシの問題を防ぐために、CPU使用率の高い瞬間にGCが実行されないようにする可能性があります。
- 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;
}