Я смотрю на D сегодня, и на поверхности это выглядит довольно удивительно. Мне нравится, как он включает в себя множество конструкций более высокого уровня непосредственно на этом языке, поэтому не нужно использовать глупые хаки или сложные методы. Одна вещь, которая действительно беспокоит меня, если GC. Я знаю, что это большие проблемы, и я много читал об этом.
Мои собственные простые тесты, спроецированные на вопрос, показывают, что GC очень медленный. Более 10 раз медленнее, чем прямой С++, делающий то же самое. (очевидно, тест напрямую не преобразуется в реальный мир, но удар по производительности является экстремальным и замедляется, когда происходит реальный мир, который ведет себя одинаково (быстро выделяя множество мелких объектов)
Я занимаюсь написанием звукового приложения с низкой задержкой в реальном времени, и возможно, что GC испортит производительность приложения, чтобы сделать его почти бесполезным. В каком-то смысле, если у него есть какие-либо проблемы, это разрушит аудиоспектр в реальном времени, что намного более важно, поскольку в отличие от графики звук работает с гораздо более высокой частотой кадров (44000+ против 30-60). (из-за его низкой латентности он более важен, чем стандартный аудиоплеер, который может накапливать значительные объемы данных).
Отключение GC улучшило результаты примерно до 20% кода С++. Это важно. Я дам код в конце для анализа.
Мои вопросы:
- Насколько сложно заменить D GC стандартной реализацией интеллектуальных указателей, чтобы библиотеки, которые полагались на GC, все еще можно было использовать. Если я полностью удалю GC, я потеряю много работы, так как у D уже есть библиотеки ограничений по сравнению с С++.
- Может ли GC.Disable временно приостанавливать сборку мусора (предотвращение запуска потока GC) и GC.Enable выбрать резервную копию там, где она была остановлена. Поэтому я могу потенциально отключить GC от работы в высокопроизводительных моментах, чтобы предотвратить проблемы с задержкой.
- Есть ли способ заставить шаблон не использовать GC последовательно. (это потому, что я не программировал в D, и когда я начинаю писать очки, которые не используют GC, я бы хотел быть уверен, что не забываю реализовать их собственную очистку.
- Можно ли легко заменить GC в D? (не то, что я хочу, но может быть интересно поиграть с разными методами GC в один прекрасный день... это похоже на 1, я полагаю)
То, что я хотел бы сделать, это торговля памятью для скорости. Мне не нужно, чтобы GC запускался каждые несколько секунд. На самом деле, если я смогу правильно реализовать свое собственное управление памятью для своих структур данных, то, скорее всего, он не будет запускаться очень часто. Возможно, мне придется запускать его, только когда память становится скудной. Однако из того, что я прочитал, чем дольше вы дожидаетесь, тем быстрее это будет. Поскольку в моем приложении обычно бывают случаи, когда я могу уйти с вызовом без проблем, это поможет смягчить некоторое давление (но опять же, могут быть часы, когда я не смогу назвать это).
Я не беспокоюсь об ограничениях памяти. Я бы предпочел "тратить" память на скорость (конечно же, до точки). Прежде всего, это проблемы с задержкой.
Из того, что я прочитал, я могу, по крайней мере, пойти по пути C/С++, пока я не использую никаких библиотек или языковых конструкций, которые полагаются на GC. Проблема в том, что я не знаю тех, которые делают. Я видел строку, новую и т.д., Но означает ли это, что я не могу использовать строковые строки, если я не включаю GC?
Я читал в некоторых сообщениях об ошибках, что GC может быть действительно глючным, и это может объяснить его проблемы с производительностью?
Кроме того, D использует немного больше памяти, на самом деле D заканчивается из памяти перед программой на С++. Я предполагаю, что это примерно на 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 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();
}
Код С++
#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;
}