о куче
От: Pavel Dvorkin Россия  
Дата: 09.12.05 08:47
Оценка: 2 (2)
Вот такая странная идея мне в голову пришла вчера во время бессоницы. Что-то меня на странные идеи потянуло

Память выделяют в куче. Реализация кучи в С++ и в управляемой среде делается по-разному. Обсуждать сейчас не буду, и тот и другой метод имеют свои преимущества и недостатки.

А если реализовать кучу следующим образом ?

Каждый объект, размещаемый в куче, имеет свой размер s. Разделим их по размеру на 3 категории — малые (s <= n), средние ( n < s < =N) и большие ( s > N). Численные значения надо определить экспериментально.

Для малых объектов создадим массивы

массив0 — для объектов с размером от 1 до 8 байт
массив1 — от 9 до 16
массив2 от 17 до 24

и т.д.

Для каждого малого объекта будем выделять память, кратную 8 байт, т.е. отнесем его к массиву0, или массиву1 и т.д. Это, в сущности, и сейчас делается в куче С++ — паять выделяется в размере, округленном в верхнюю сторону до 8 (или до 16 ?).

На базе этих массивов реализуем линейный список свободных ячеек. Для этого достаточно расписать элементы этих массивов указателем на следующий в массиве элемент. При взятии элемента из списка берется элемент, на который показывает pList и он продвигается, при освобождении — освобожденный элемент добавляется в список.

Кстати, эти массивы — не обязательно массивы в истинном смысле этого слова. Они могут лежать в памяти кусками — несмежными страницами, т.е. при необходимости расти.

Теперь выделение памяти для малых объектов сводится просто к взятию элемента из списка, а освобождение памяти (хоть delete, хоть GC) — к возвращению в список. Для неуправляемой кучи не требуется поиск подходящего блока, разбиение его и т.д. Для управляемой кучи не требуется сжатия кучи.

К малым объектам будут отнесены

большинство одиночных экземпляров классов
небольшие массивы (POINT[3], к примеру)
текстовые строки малого и среднего размера.

Для средних объектов оставляем все как есть сейчас. К ним будут отнесены средних размеров массивы, очень крупные экземпляры классов и большие текстовые строки. Как правило, таких объектов в программе намного меньше, чем "малых" переменных.

Для больших объектов память выделяем/освобождаем с помощью VirtualAlloc/Free, т.е округляем до размера страницы в верхнюю сторону. Оверхед при этом незначителен. Если, к примеру, большими считать объекты с размером более 100 Кб, то оверхед будет не более 4%, а при 1 Мб — вообще 0.4%. Можно пренебречь.

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

Подводный камень, который я вижу

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

Насколько я знаю, нечто подобное есть в ядре — ассоциативные списки, с фиксированным размером элементов, наиболее употребительные размеры. Почему бы это не реализовать и в приложениях 3 кольца ?

Все. я готов к критике
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.