Если бы я начал описывать, как построить связный список или зачем нужно выравнивание, то читатели, до которых я хотел донести информацию, плюнули бы на середине и закрыли страницу.
Статья расчитана на тех, кто уже пытался писать свои аллокаторы. Акцент в статье — на перегрузке операторов и синтаксических конструкциях для работы со своими аллокаторами, как с минимальными затратами преобразовать существующую программу.
Тривиальные классы я сначала не хотел приводить, затем засунул под спойлер.
1. Удаление оптимизатором пустого цикла не происходит, тогда время было бы 0. Тем более, в отдельных случаях я достиг времени, как у CLR, так что сравнение честное.
2. Как раз первый пример и устраняет фрагментацию. Объекты разных типов лежат в непересекающихся пулах, а внутри пула фрагментация значения не имеет. Поиск свободного блока — O(1), все блоки в пуле одинаковые, поэтому нет случая, когда много свободного места по мелочи, а взять нечего.
3. Первый пример предусматривает возврат неиспользуемой памяти, смотрите внимательнее. Если алгоритм съест всю память, то значит она вся нужна (выделена)
4. Ну отлично. Проверьте всё же класс BlockAlloc, ведь переделки программы совсем тривиальные (и ещё вернуть надо в состояние до-GC, когда delete не забывали вызывать)
Эх, FastMM… Юзал в дельфи для поиска утечек памяти. Очень удобно — при закрытии приложения каждая утечка описана со stacktrace-ом, где сделано выделение.
В MSVC всё печальнее — только список утечек, без стека, если включать _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF)
Маленькие объекты должны быть struct, а не class.
Создать массив достаточной длины из struct, и везде ссылаться на объекты не по ссылке, а по индексу в массиве.
Ваш подход описан в первой части. Честно говоря, в рабочей версии управление большими страницами я тоже сделал связным списком (данные на следующую страницу — в хидере страницы). Но, чтобы не перегружать статью, переписал на vector<>, на быстродействие это окажет минимальное влияние.
В статье описаны две совершенно разных подхода:
1. Блоки одинакового размера, с активным выделением-освобождением
2. Разношёрстные блоки с быстрым выделением, но освобождаются только все сразу (должны иметь одинаковое время жизни смерти)
Да, во втором случае, в пуле могуть быть разные объекты, но т.к. удаление запрещено, выделение памяти очень простое и разделение по пулам мне кажется, не даст ускорения (с чего бы...)
hole punching не поюзаешь для коммерческих решений. это же эксплуатация дыры, по сути.
проверял, оно работает далеко не везде: на ADSL-модеме ZyXEL работало, а на роутерах с RouterOS или FreeBSD (NAT силами ipfw) — увы. то есть, надёжный способ — релеи
кроме того, для координации hole punching нужен сторонний сервер, а он уже может ответить, что фокус не удался и трафик надо гнать через релей, даже когда роутеры клиентов позволили бы прямое соединение
судя по примерам, автор говорит о программах, меняющих свою логику под воздействием входных данных.
на любой интерпретатор можно посмотреть в двух точек зрения:
— он выполняет поступающие команды строго по порядку и ничего неожиданного в нём нет.
— при поступлении программы он начинает работать по логике программы, совершенно непредсказуемо на момент создания интерпретатора
кто переводит с русского на английский — интерпретатор или подаваемая на него программа? а если провести грань между ними сложно, как в вышеприведённой программе STUDENT?
да, и ещё проблема этого кода — создание CValue вне наследника CStructBase. тогда этот CValue допишется в последний созданный экземпляр CStructBase (который может быть уже разрушен).
по-хорошему, после завершения всех конструкторов членов CMyStruct надо сделать g_mapByThreadId[GetCurrentThreadId()] = NULL
что-то не соображу, как это сделать автоматически, чтобы не повторять в каждом конструкторе CMyStruct
Как я его раньше не видел — ума не приложу
Статья расчитана на тех, кто уже пытался писать свои аллокаторы. Акцент в статье — на перегрузке операторов и синтаксических конструкциях для работы со своими аллокаторами, как с минимальными затратами преобразовать существующую программу.
Тривиальные классы я сначала не хотел приводить, затем засунул под спойлер.
очень давно тестил на Celeron D 320, были другие результаты.
2. Как раз первый пример и устраняет фрагментацию. Объекты разных типов лежат в непересекающихся пулах, а внутри пула фрагментация значения не имеет. Поиск свободного блока — O(1), все блоки в пуле одинаковые, поэтому нет случая, когда много свободного места по мелочи, а взять нечего.
3. Первый пример предусматривает возврат неиспользуемой памяти, смотрите внимательнее. Если алгоритм съест всю память, то значит она вся нужна (выделена)
4. Ну отлично. Проверьте всё же класс BlockAlloc, ведь переделки программы совсем тривиальные (и ещё вернуть надо в состояние до-GC, когда delete не забывали вызывать)
В MSVC всё печальнее — только список утечек, без стека, если включать _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF)
Может, кто посоветует leak detectors для MSVC.
Создать массив достаточной длины из struct, и везде ссылаться на объекты не по ссылке, а по индексу в массиве.
В статье описаны две совершенно разных подхода:
1. Блоки одинакового размера, с активным выделением-освобождением
2. Разношёрстные блоки с быстрым выделением, но освобождаются только все сразу (должны иметь одинаковое время
жизнисмерти)проверял, оно работает далеко не везде: на ADSL-модеме ZyXEL работало, а на роутерах с RouterOS или FreeBSD (NAT силами ipfw) — увы. то есть, надёжный способ — релеи
кроме того, для координации hole punching нужен сторонний сервер, а он уже может ответить, что фокус не удался и трафик надо гнать через релей, даже когда роутеры клиентов позволили бы прямое соединение
на любой интерпретатор можно посмотреть в двух точек зрения:
— он выполняет поступающие команды строго по порядку и ничего неожиданного в нём нет.
— при поступлении программы он начинает работать по логике программы, совершенно непредсказуемо на момент создания интерпретатора
кто переводит с русского на английский — интерпретатор или подаваемая на него программа? а если провести грань между ними сложно, как в вышеприведённой программе STUDENT?
парадокс описан ещё Джоном Сёрлем
наверное, я дурак ))
по-хорошему, после завершения всех конструкторов членов CMyStruct надо сделать g_mapByThreadId[GetCurrentThreadId()] = NULL
что-то не соображу, как это сделать автоматически, чтобы не повторять в каждом конструкторе CMyStruct
в с++
__declspec(thread) CStructBase* currentClass;
в C#, Pascal и т.п. тоже есть аналогичные windows-specific кейворды ([ThreadStatic], threadvar)