С самого начала следует отметить, что, по их словам, «общепринятым мнением является разработка технологии обмена сообщениями с малой задержкой, требующей использования неуправляемого C ++ или языка ассемблера».В частности, они говорят о некоем случае, когда люди часто отвергают решение .NET (или Java) из-под контроля.В этом отношении, относительно наивное решение C ++, вероятно, также не получило бы оценку.
Еще одна вещь, которую следует учесть здесь, это то, что они по сути не столько избавились от GC, сколько заменили его -там есть код, управляющий временем жизни объекта, но это их собственный код.
Есть несколько различных способов сделать это вместо этого.Вот одинСкажем, мне нужно создать и уничтожить несколько объектов Foo во время работы моего приложения.Создание Foo параметрируется с помощью int, поэтому обычный код будет выглядеть следующим образом:
public class Foo
{
private readonly int _bar;
Foo(int bar)
{
_bar = bar;
}
/* other code that makes this class actually interesting. */
}
public class UsesFoo
{
public void FooUsedHere(int param)
{
Foo baz = new Foo(param)
//Do something here
//baz falls out of scope and is liable to GC colleciton
}
}
Весьма другой подход:
public class Foo
{
private static readonly Foo[] FOO_STORE = new Foo[MOST_POSSIBLY_NEEDED];
private static Foo FREE;
static Foo()
{
Foo last = FOO_STORE[MOST_POSSIBLY_NEEDED -1] = new Foo();
int idx = MOST_POSSIBLY_NEEDED - 1;
while(idx != 0)
{
Foo newFoo = FOO_STORE[--idx] = new Foo();
newFoo._next = FOO_STORE[idx + 1];
}
FREE = last._next = FOO_STORE[0];
}
private Foo _next;
//Note _bar is no longer readonly. We lose the advantages
//as a cost of reusing objects. Even if Foo acts immutable
//it isn't really.
private int _bar;
public static Foo GetFoo(int bar)
{
Foo ret = FREE;
FREE = ret._next;
return ret;
}
public void Release()
{
_next = FREE;
FREE = this;
}
/* other code that makes this class actually interesting. */
}
public class UsesFoo
{
public void FooUsedHere(int param)
{
Foo baz = Foo.GetFoo(param)
//Do something here
baz.Release();
}
}
Дополнительные сложности могут быть добавлены, если вы многопоточны (хотядля действительно высокой производительности в неинтерактивной среде вам может потребоваться один поток или отдельные хранилища классов Foo для каждого потока), и если вы не можете заранее предсказать MOST_POSSIBLY_NEEDED (самое простое - создать новый Foo () по мере необходимости, но не выпускайте их для GC, что можно легко сделать в приведенном выше коде, создав новый Foo, если FREE._next имеет значение null).
Если мы разрешаем небезопасный код, мы можем получить еще большие преимущества, имея Fooструктура (и, следовательно, массив, содержащий непрерывную область памяти стека), _next - указатель на Foo, и GetFoo (), возвращающий указатель.
Является ли это тем, чем на самом деле занимаются эти люди, я, конечно,не могу сказать, но вышеизложенное не позволяет активировать GC.Это будет быстрее только в условиях очень высокой пропускной способности, а если нет, то позволить GC делать свое дело, вероятно, лучше (GC действительно помогает вам, несмотря на то, что 90% вопросов о том, что он воспринимает это как «большой плохой»).Есть и другие подходы, которые так же избегают GC.В C ++ операторы new и delete могут быть переопределены, что позволяет изменить поведение создания и уничтожения по умолчанию, и обсуждения того, как и почему это можно сделать, могут вас заинтересовать.
Практический вывод из этогоэто когда объекты либо содержат ресурсы, кроме памяти, которые дороги (например, соединения с базами данных), либо «изучают», как они продолжают использоваться (например, XmlNameTables).В этом случае пул объектов полезен (соединения ADO.NET делают это за кулисами по умолчанию).В этом случае, хотя простой путь - путь, поскольку дополнительные издержки с точки зрения памяти не имеют значения.Вы также можете отказаться от объектов при конфликте блокировок (вы стремитесь повысить производительность, и конфликт блокировок нанесет им больший вред, чем при отказе от объекта), что, я сомневаюсь, сработает в их случае.