GC or not GC
От: StanislavK Великобритания  
Дата: 23.09.13 13:34
Оценка: 14 (1)
Неравно прочитал пост на блоге одного умного дядьки и нарвался на документ, который напомнил мне один из июльских постов
Автор: A13x
Дата: 10.07.13
на форуме. Для тех кто не помнит или не хочет вспоминать — была там ссылка на "Очень интересный, глубокий и познавательный пост о проблемах в мобильной разработке." Пост был так себе, просто buzz и эмоции. Помимо прочего, этот пост проехался по GC, и как бы невзначай упоминал ARC, который "It isn’t GC, it isn’t anything like GC, it performs nothing like GC, it does not have the power of GC, it does not break retain cycles, it does not sweep anything, it does not scan anything. Period, end of story, not garbage collection". И, в качестве доказательства того, что GC сосет был приведен график из документа, который сравнивает не понятно что, с непонятно чем и делает соответствующие выводы. Про то как себя ведет ARC нигде не говорится, но очень толсто подразумевается.

В общем, сейчас я нашел на документ несоклько иного содержания:

http://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf

Суть, которого сводится к следующему, логичному, но почему-то не очевидному выводу, который, в общем, лежит на поверхности:

We have shown that tracing (под tracing имеется ввиду то, что принято обычно понимать под GC) and reference counting garbage collection, which were previously thought to be very different, in fact share the exact same structure and can be viewed as duals of each other. ...This explains why highly optimized tracing and reference counting collectors have surprisingly similar performance characteristics.

В самом деле, как бы память не чистилась, количесво усилий, которые надо для этого приложить не становятся меньше. Естественно, что сравниваемые системы управления памятью должны иметь схожие функциональные характеристики.
Re: GC or not GC
От: A13x США  
Дата: 23.09.13 16:15
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>...

SK>http://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf

SK>Суть, которого сводится к следующему, логичному, но почему-то не очевидному выводу, который, в общем, лежит на поверхности:


SK>We have shown that tracing (под tracing имеется ввиду то, что принято обычно понимать под GC) and reference counting garbage collection, which were previously thought to be very different, in fact share the exact same structure and can be viewed as duals of each other. ...This explains why highly optimized tracing and reference counting collectors have surprisingly similar performance characteristics.


SK>В самом деле, как бы память не чистилась, количесво усилий, которые надо для этого приложить не становятся меньше. Естественно, что сравниваемые системы управления памятью должны иметь схожие функциональные характеристики.


Насколько я понял из статьи под reference counting GC подразумевался именно специфический сборщик мусора, основанный на подсчете ссылок, т.е. нечто большее чем smart pointers а-la boost::shared_ptr.
В частности сборщик мусора "умеет" больше чем просто потокобезопасно декрементировать ссылки на объект, но и убирать мусор в виде графа циклически ссылающихся друг на друга объектов, что предполагает несколько иную сложность реализации.
Re[2]: GC or not GC
От: StanislavK Великобритания  
Дата: 24.09.13 07:39
Оценка:
Здравствуйте, A13x, Вы писали:

SK>>http://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf

SK>>В самом деле, как бы память не чистилась, количесво усилий, которые надо для этого приложить не становятся меньше. Естественно, что сравниваемые системы управления памятью должны иметь схожие функциональные характеристики.

A>Насколько я понял из статьи под reference counting GC подразумевался именно специфический сборщик мусора, основанный на подсчете ссылок, т.е. нечто большее чем smart pointers а-la boost::shared_ptr.

A>В частности сборщик мусора "умеет" больше чем просто потокобезопасно декрементировать ссылки на объект, но и убирать мусор в виде графа циклически ссылающихся друг на друга объектов, что предполагает несколько иную сложность реализации.

С этим никто не спорит.
На самом деле даже минимальный "сборщик", как тот же shared_ptr должен "уметь" (хотя и косвенно) несоклько больше, чем просто считать ссылки. Память надо еще выделить и удалить.
Re[3]: GC or not GC
От: A13x США  
Дата: 24.09.13 13:38
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>Здравствуйте, A13x, Вы писали:


SK>>>http://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf

SK>>>В самом деле, как бы память не чистилась, количесво усилий, которые надо для этого приложить не становятся меньше. Естественно, что сравниваемые системы управления памятью должны иметь схожие функциональные характеристики.

A>>Насколько я понял из статьи под reference counting GC подразумевался именно специфический сборщик мусора, основанный на подсчете ссылок, т.е. нечто большее чем smart pointers а-la boost::shared_ptr.

A>>В частности сборщик мусора "умеет" больше чем просто потокобезопасно декрементировать ссылки на объект, но и убирать мусор в виде графа циклически ссылающихся друг на друга объектов, что предполагает несколько иную сложность реализации.

SK>С этим никто не спорит.

SK>На самом деле даже минимальный "сборщик", как тот же shared_ptr должен "уметь" (хотя и косвенно) несоклько больше, чем просто считать ссылки. Память надо еще выделить и удалить.

Непосредственно выделение памяти, насколько я знаю, не является задачей умного указателя.
Тот же shared_ptr, да и вообще все известные мне умные указатели не содержат в себе какого-то специфического аллокатора памяти.

Тогда уж стоит сравнивать специфический аллокатор памяти общего назначения и сборщик мусора. Тут сравнивать сложно, т.к. насколько я знаю подобного рода аллокаторы обычно плохо подходят для большого количества часто выделяемых и удаляемых мелких объектов.
Для выделения памяти под небольшие объекты иногда используют специфические аллокаторы, которые очень быстры, достаточно экономны и предсказуемо ведут себя в стрессовых условиях.
Re[4]: GC or not GC
От: StanislavK Великобритания  
Дата: 24.09.13 16:19
Оценка:
Здравствуйте, A13x, Вы писали:

SK>>>>http://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf

SK>>>>В самом деле, как бы память не чистилась, количесво усилий, которые надо для этого приложить не становятся меньше. Естественно, что сравниваемые системы управления памятью должны иметь схожие функциональные характеристики.

A>Непосредственно выделение памяти, насколько я знаю, не является задачей умного указателя.

A>Тот же shared_ptr, да и вообще все известные мне умные указатели не содержат в себе какого-то специфического аллокатора памяти.
Я же написал, что косвенно. То, что он этим не заннимается, не значит, что это не делается. По сути, при измерениях производительности работы системы выделения/освобождения памяти, смысла разделять эти вещи нет.


A>Тогда уж стоит сравнивать специфический аллокатор памяти общего назначения и сборщик мусора. Тут сравнивать сложно, т.к. насколько я знаю подобного рода аллокаторы обычно плохо подходят для большого количества часто выделяемых и удаляемых мелких объектов.

A>Для выделения памяти под небольшие объекты иногда используют специфические аллокаторы, которые очень быстры, достаточно экономны и предсказуемо ведут себя в стрессовых условиях.

Кстати, насколько быстро? Я в С++ уже не бум-бум, так, что могу и налажать с тестами. GC в Java, вот, может вычистить около 650mb за 7ms без full stop (статистика из GC лога продашн системы), размер объектов 3-6Kb, т.е. где-то 133000 объектов. Как там быстрый С++ в этом плане? Быстрый и достаточно экономный у меня справился за 200ms, про стандартный даже не буду упоминать. С++ тест внизу, статистики по джаве взял просто из GC лога.

// alloc_cpp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

typedef Loki::SmallObject<LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL, 256*1024, 5000, 32> MyAllocatorSingleton;

void allocate(std::pair<size_t, byte*>& pair) {
    pair.second = new byte[pair.first];
}

void allocate_loki(std::pair<size_t, byte*>& pair) {
    pair.second = (byte*)MyAllocatorSingleton::operator new(pair.first);
}

void deallocate(std::pair<size_t, byte*>& pair) {
    delete[] pair.second;
    pair.second = (byte*)NULL;
}

void deallocate_loki(std::pair<size_t, byte*>& pair) {
    MyAllocatorSingleton::operator delete(pair.second, pair.first);
    pair.second = (byte*)NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
    LARGE_INTEGER frequency;
    LARGE_INTEGER start;
    LARGE_INTEGER end;
    double interval;

    const int nElements = 1333000;
    std::vector<std::pair<size_t, byte*>> vect(nElements);
    for(int i = 0; i != nElements; ++i) {
        std::pair<size_t, byte*> allocPair(3000 + ::rand()%2000, (byte*)NULL);
    }
    std::for_each(vect.begin(), vect.end(), allocate_loki);

    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&start);

    std::for_each(vect.begin(), vect.end(), deallocate_loki);

    QueryPerformanceCounter(&end);
    interval = (double) (end.QuadPart - start.QuadPart) / frequency.QuadPart;

    printf("%f\n", interval);
    ::getchar();

    return 0;
}



Хотя ладно, справедливости ради решил сделать простенький тест для java:
        Random rnd = new Random();
        final int initialCapacity = 133000;
        List<byte[]> arrList = new ArrayList<byte[]>(initialCapacity);
        for(int i = 0; i != initialCapacity; ++i) {
            arrList.add(new byte[3000+rnd.nextInt(2000)]);
        }

        arrList.clear();
        System.gc();
        System.gc();


Измерять суммированием временя проведенном в gc во время теста (-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails). Тут получилось больше чем 8, где-то 16-20ms, но это только потому, что по дефолту памяти дается меньше, чем стоит у продакшн машины.
Re[5]: GC or not GC
От: StanislavK Великобритания  
Дата: 24.09.13 19:08
Оценка:
Ахаха. Буквально немного ошибся. Завтра еще разок прогоню

SK>
SK>    const int nElements = 1333000;
SK>



SK>
SK>        final int initialCapacity = 133000;
SK>
Re[6]: GC or not GC
От: StanislavK Великобритания  
Дата: 26.09.13 09:35
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>Ахаха. Буквально немного ошибся. Завтра еще разок прогоню

Новые тесты. Тесты стали немного более разумными, настолько насколько это возможно для подобного рода бенчмарков. Измеряется только освобождение памяти.
Немного переработал так, чтобы у java GC не вызывался major gc, так как обычно если это случается, то с приложением что-то не так. Все извесные мне серверные приложения успешно его избегают.
Попутно обнаружил, что аллокатор loki очень чувствителен к настройкам и немного вправо или в лево может зарубить производительность. Надо все мерить и пробовать. В общем, это значит, что я мог и накосячить.

Результаты — GC справилься за 265ms (cуммарное время в GC), loki за 1330ms. GC при это жрет в разы больше пямяти (раза в 3.5).
Выводы делайте сами. GC быстр, если его правильно готовить, но за все надо платить.

Код:

typedef Loki::SmallObject<LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL, 256*1024, 812, 32> MyAllocatorSingleton;

void PrintMemoryInfo( DWORD processID );
    
void allocate(std::pair<size_t, byte*>& pair) {
    pair.second = new byte[pair.first];
}

void allocate_loki(std::pair<size_t, byte*>& pair) {
    pair.second = (byte*)MyAllocatorSingleton::operator new(pair.first);
}

void deallocate(std::pair<size_t, byte*>& pair) {
    delete[] pair.second;
    pair.second = (byte*)NULL;
}

void deallocate_loki(std::pair<size_t, byte*>& pair) {
    MyAllocatorSingleton::operator delete(pair.second, pair.first);
    pair.second = (byte*)NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
    LARGE_INTEGER frequency;
    LARGE_INTEGER start;
    LARGE_INTEGER end;
    double interval = 0;

    const int nIteration = 100;
    const int nElements = 100000;

    ::QueryPerformanceFrequency(&frequency);

    for(int i = 0; i != nIteration; ++i) {
        std::vector<std::pair<size_t, byte*>> vect;
        for(int el = 0; el != nElements; ++el) {
            std::pair<size_t, byte*> allocPair((512 + 15 + ::rand()%300), (byte*)NULL);
            vect.push_back(allocPair);
        }
        std::for_each(vect.begin(), vect.end(), allocate_loki);

        ::QueryPerformanceCounter(&start);
        std::for_each(vect.begin(), vect.end(), deallocate_loki);
        ::QueryPerformanceCounter(&end);

        interval += (double) (end.QuadPart - start.QuadPart) / frequency.QuadPart;
    }

    printf("%f\n", interval);
    PrintMemoryInfo( ::GetCurrentProcessId() );

    ::getchar();


    return 0;
}

void PrintMemoryInfo( DWORD processID )
{
    HANDLE hProcess;
    PROCESS_MEMORY_COUNTERS pmc;

    // Print the process identifier.
    printf( "\nProcess ID: %u\n", processID );

    // Print information about the memory usage of the process.
    hProcess = ::OpenProcess(  PROCESS_QUERY_INFORMATION |
                                    PROCESS_VM_READ,
                                    FALSE, processID );
    if (NULL == hProcess)
        return;

    __try{
        if ( ::GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) )
        {
            printf( "\tPageFaultCount: %08u\n", pmc.PageFaultCount );
            printf( "\tPeakWorkingSetSize: %08uK\n", 
                      pmc.PeakWorkingSetSize/1024 );
            printf( "\tWorkingSetSize: %08u\n", pmc.WorkingSetSize/1024 );
            printf( "\tQuotaPeakPagedPoolUsage: %08uK\n", 
                      pmc.QuotaPeakPagedPoolUsage/1024 );
            printf( "\tQuotaPagedPoolUsage: %08uK\n", 
                      pmc.QuotaPagedPoolUsage/1024 );
            printf( "\tQuotaPeakNonPagedPoolUsage: %08uK\n", 
                      pmc.QuotaPeakNonPagedPoolUsage/1024 );
            printf( "\tQuotaNonPagedPoolUsage: %08uK\n", 
                      pmc.QuotaNonPagedPoolUsage/1024 );
            printf( "\tPagefileUsage: %08uK\n", pmc.PagefileUsage/1024 ); 
            printf( "\tPeakPagefileUsage: %08uK\n", 
                      pmc.PeakPagefileUsage/1024 );
        }
    }
    __finally {
        ::CloseHandle( hProcess );
    }
}




public class GCTest {
    public static void main(String[] args) throws Exception {
        Random rnd = new Random();

        // warm up
        runTest(rnd);
        System.gc();

        System.out.println("**********************");
        System.out.println("**********************");
        System.out.println("**********************");
        System.out.println("**********************");

        runTest(rnd);
        System.gc();
    }

    private static void runTest(Random rnd) {
        final int nIteration = 100;
        final int nElements = 100000;

        for(int i = 0; i != nIteration; ++i) {
            byte[][] arrList = new byte[nElements][];
            for(int el = 0; el != nElements; ++el) {
                arrList[el] = new byte[512+rnd.nextInt(300)];
            }
        }
    }
}
Re[7]: GC or not GC
От: Blazkowicz Россия  
Дата: 26.09.13 10:39
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>Все извесные мне серверные приложения успешно его избегают.

Уже писал в предыдущей теме. Напомню и в этой. Мне кажется, что существует принципиальная разница между серверным GC, который, обычно служит единственному приложению с достаточно предсказуемым поведением и требованиями. И мобильным GC, который обслуживает все приложения, запущеные пользователем, поведение которых не предсказуемо.
Re[8]: GC or not GC
От: StanislavK Великобритания  
Дата: 26.09.13 11:27
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, StanislavK, Вы писали:


SK>>Все извесные мне серверные приложения успешно его избегают.

B>Уже писал в предыдущей теме. Напомню и в этой. Мне кажется, что существует принципиальная разница между серверным GC, который, обычно служит единственному приложению с достаточно предсказуемым поведением и требованиями. И мобильным GC, который обслуживает все приложения, запущеные пользователем, поведение которых не предсказуемо.

"Garbage collections are independent between applications, even though they are sharing some memory, since each application is in a separate process, with a separate VM and separate heaps."
Source: http://davidehringer.com/software/android/The_Dalvik_Virtual_Machine.pdf
Re[9]: GC or not GC
От: Blazkowicz Россия  
Дата: 26.09.13 11:33
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>"Garbage collections are independent between applications, even though they are sharing some memory, since each application is in a separate process, with a separate VM and separate heaps."

SK>Source: http://davidehringer.com/software/android/The_Dalvik_Virtual_Machine.pdf
А это не так важно. Будь у них общая куча или отдельные, важно то что тонко настроить GC под каждое приложение возможности нет.
Re[10]: GC or not GC
От: StanislavK Великобритания  
Дата: 26.09.13 12:48
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

SK>>"Garbage collections are independent between applications, even though they are sharing some memory, since each application is in a separate process, with a separate VM and separate heaps."

SK>>Source: http://davidehringer.com/software/android/The_Dalvik_Virtual_Machine.pdf
B>А это не так важно. Будь у них общая куча или отдельные, важно то что тонко настроить GC под каждое приложение возможности нет.
Единственная настройка, которая имеет принципиальное значение, это размер хипа. Даже в мобильниках его можно достаточно точно предсказать.
Тонкая настройка требуется только тогда когда или проблемы с приложением (написанно не через правильное место) или когда приложение сильно специфическое.
Re[7]: GC or not GC
От: Аноним  
Дата: 26.09.13 14:08
Оценка:
SK>Здравствуйте, StanislavK, Вы писали:

SK>Немного переработал так, чтобы у java GC не вызывался major gc, так как обычно если это случается, то с приложением что-то не так. Все извесные мне серверные приложения успешно его избегают.


Что то не очень верится в это. Если эти серверные приложения избегают major collection, значит они не имеют ни одного объекта в tenured. Очень сомнительно.
Например помнятся случаи, когда IMB делали многопроходную дефрагментацию (compacting) в tenured из за того, что было довольно много случаев, когда эта дефрагментация
шла десятки минут в больших приложениях на вебсфере. Ну а если сравнивать только tenured, то общепринятый аналог этому в неуправляемых приложениях был бы тривиальный пул, который грохется одной командой со всеми объектами там находящимися.
Re[8]: GC or not GC
От: Blazkowicz Россия  
Дата: 27.09.13 06:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Если эти серверные приложения избегают major collection, значит они не имеют ни одного объекта в tenured.

Нет, не значит. Это значит что tenured заполнен до какого-то уровня и больше не растет.
Re: GC or not GC
От: vsb Казахстан  
Дата: 27.09.13 06:34
Оценка:
У ARC недостаток в сравнение с GC — надо помнить где циклические ссылки и разрывать эти циклы (weak reference обычно). На практике, имхо, это делать несложно и проблем с этим не возникает. Важнейшее достоинство — предсказуемость времени освобождения памяти.
Re[8]: GC or not GC
От: StanislavK Великобритания  
Дата: 27.09.13 10:16
Оценка:
Здравствуйте, Аноним, Вы писали:

SK>>Здравствуйте, StanislavK, Вы писали:


SK>>Немного переработал так, чтобы у java GC не вызывался major gc, так как обычно если это случается, то с приложением что-то не так. Все извесные мне серверные приложения успешно его избегают.

А>Что то не очень верится в это. Если эти серверные приложения избегают major collection, значит они не имеют ни одного объекта в tenured. Очень сомнительно.
Как уже говорили, это просто значит, приложение не часто создает долго живущие объекты. Например, загрузило граф при старте, а потом только обрабатывает запромы по этому графу и не слишком часто его апдейтит. Или создает объекты которые не живут дольше нескольких секунд, например, ордера в трейдинговых системах.
Но, на самом деле, есть правда в ваших словах. В веб приложениях сессия может создаваться и жить до несокльких десятков минут и тогда эти данные, конечно, состарятся. В этом случае я бы вынес это дело в offheap, будет немного медленнее на доступ, но зато без full gc.

А>Например помнятся случаи, когда IMB делали многопроходную дефрагментацию (compacting) в tenured из за того, что было довольно много случаев, когда эта дефрагментация

А>шла десятки минут в больших приложениях на вебсфере. Ну а если сравнивать только tenured, то общепринятый аналог этому в неуправляемых приложениях был бы тривиальный пул, который грохется одной командой со всеми объектами там находящимися.
кто такой IMB?
а вот не надо пользоваться всякими там вебсферами Вобщем, как я уже сказал, в вебаппликухах есть проблема. Но она решается, хотя и надо немного для этого постараться.
Re[2]: GC or not GC
От: StanislavK Великобритания  
Дата: 27.09.13 10:35
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>У ARC недостаток в сравнение с GC — надо помнить где циклические ссылки и разрывать эти циклы (weak reference обычно). На практике, имхо, это делать несложно и проблем с этим не возникает. Важнейшее достоинство — предсказуемость времени освобождения памяти.


Говорить про предсказуемость тут не совсем корректно по причине того, что ее просто нет. А нет ее потому, что не известно, что удалается. Если удаляется объкт, то возможно должен и удалиться весь граф, началом которого он являеся. Размер этого графа это одна неизвестная. Вторая незвестная это то, что на объекты в графе может ссылаться кто-нибудь еще и в этом случае они не будут удалены. Т.е., строго говоря, не известно заранее сколько объектов удалается, соответственно не изветсно и сколько времени это займет.

Единственное от чего спасает ARC, это full GC, но чаще всего если случается full gc, то у приложения просто проблемы, которые надо фиксить, а не пинать на GC.
Re[3]: GC or not GC
От: vsb Казахстан  
Дата: 27.09.13 11:08
Оценка:
Здравствуйте, StanislavK, Вы писали:

vsb>>У ARC недостаток в сравнение с GC — надо помнить где циклические ссылки и разрывать эти циклы (weak reference обычно). На практике, имхо, это делать несложно и проблем с этим не возникает. Важнейшее достоинство — предсказуемость времени освобождения памяти.


SK>Говорить про предсказуемость тут не совсем корректно по причине того, что ее просто нет. А нет ее потому, что не известно, что удалается. Если удаляется объкт, то возможно должен и удалиться весь граф, началом которого он являеся. Размер этого графа это одна неизвестная. Вторая незвестная это то, что на объекты в графе может ссылаться кто-нибудь еще и в этом случае они не будут удалены. Т.е., строго говоря, не известно заранее сколько объектов удалается, соответственно не изветсно и сколько времени это займет.


SK>Единственное от чего спасает ARC, это full GC, но чаще всего если случается full gc, то у приложения просто проблемы, которые надо фиксить, а не пинать на GC.


Ну по крайней мере можно говорить о том, что память удаляется только тогда, когда этого хочет программист, а не когда GC захочет.

Ну и, в принципе, обычно понятно, какой граф объектов держится и сколько времени займёт удаление.
Re[4]: GC or not GC
От: StanislavK Великобритания  
Дата: 27.09.13 14:13
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Здравствуйте, StanislavK, Вы писали:


SK>>Единственное от чего спасает ARC, это full GC, но чаще всего если случается full gc, то у приложения просто проблемы, которые надо фиксить, а не пинать на GC.

vsb>Ну по крайней мере можно говорить о том, что память удаляется только тогда, когда этого хочет программист, а не когда GC захочет.
Какая разница? Зачем программисту это знать? GC, как уже было замеченно, может высвободить 600mb за 6ms. Конечно, если у вас жесткое требование на latency меньше 10-15ms, то эта другая история, но это скорее экзотика.

vsb>Ну и, в принципе, обычно понятно, какой граф объектов держится и сколько времени займёт удаление.

Так же, в принципе, и у GC все понятно
Re[5]: GC or not GC
От: A13x США  
Дата: 03.10.13 03:21
Оценка:
Здравствуйте, StanislavK, Вы писали:

SK>....

SK>Кстати, насколько быстро? Я в С++ уже не бум-бум, так, что могу и налажать с тестами. GC в Java, вот, может вычистить около 650mb за 7ms без full stop (статистика из GC лога продашн системы), размер объектов 3-6Kb, т.е. где-то 133000 объектов. Как там быстрый С++ в этом плане? Быстрый и достаточно экономный у меня справился за 200ms, про стандартный даже не буду упоминать. С++ тест внизу, статистики по джаве взял просто из GC лога.

Мне кажется не совсем корректно так сравнивать, т.к. задача освободить сразу большое количество памяти не стоит. В С-подобных языках с ручным управлением памятью объекты освобождаются сразу как перестанут быть нужными.

Если нужно удалить сразу все после большого прогона, то нужно сравнивать так (в вашем варианте):


#include <stdlib.h>

// ...

void * block = malloc(estimated_mem_size); // estimated_mem_size == 600Mb
void * next_free_obj = block;

for (/* PUT CONDITION HERE */) {
  // actual allocation
  obj_t * obj = next_free_obj;
  next_free_obj += sizeof(obj_t);
  
  // do something with obj

  // now you may either:
  // [1] delete obj: next_free_obj -= sizeof(obj_t)
  // [2] keep it allocated
}

// ok, our long operation has been completed
free(block);

И вот тут вариант на С будет самым быстрым.

Хочу заметить, что для С++ автоматом вызываются деструкторы, давайте для сравнения повторим ваш прогон для объектов с finalize, например так:

// forbid inlining for C++ and java:

// C++
~MyObj() {
  if (GetTickCount() == 0L) { // any function to retrieve current time in millis to cheat compiler to forbid inlining
     exit(0); // never triggers
  }
}

// java
@Override protected void finalize() {
  if (System.currentTimeMillis() == 0L) {  // any function to retrieve current time in millis to cheat JIT to forbid inlining
     System.exit(0);
  }
}


PS: К сожалению в последнее время невероятно много работы и не удалось поучаствовать поживее в этом обсуждении.
Re[6]: GC or not GC
От: Blazkowicz Россия  
Дата: 03.10.13 07:24
Оценка:
Здравствуйте, A13x, Вы писали:

A> В С-подобных языках с ручным управлением памятью объекты освобождаются сразу как перестанут быть нужными.

Это позиционируется как недостаток по сравнению с GC, который более эффективно убирает мусор большими блоками, а не по одному объекту. С другой стороны он менее эффективно сканирует живые объекты. Необходимость в котором отсутствует при ручном управлении.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.