Эффективный диспетчер "кучи" для тяжелой маслобойки, крошечных выделений?

Более простой подход с использованием петель.

IEnumerable> GetList(IEnumerable source)
{
    while(source.Any())
    {
        var returnValue = source.TakeWhile(x=>!x.Equals("and")).ToList();
        yield return returnValue;
        source = source.Skip(returnValue.Count()+1);
    }
}

Теперь вы можете сделать,

var words = new[] { "visit", "houston", "and", "san", "antonio", "and", "austin", "and", "corpus", "christi" };
var result = GetList(words);

Выход

enter image description here

8
задан Menkboy 23 October 2008 в 00:48
поделиться

6 ответов

Возможно создать диспетчер "кучи", который очень эффективен для объектов, которые являются всеми одинаковыми размер. Вы могли создать одну из этой "кучи" для каждого размера объекта, в котором Вы нуждаетесь, или если Вы не возражаете использовать немного пространства, создаете один для 16-байтовых объектов, один для 32, и один для 64. Максимум наверху составил бы 31 байт для 33-байтового выделения (который пойдет на 64 blocksize "кучи").

6
ответ дан 5 December 2019 в 10:45
поделиться

Чтобы подробно остановиться, что Greg Hewgill говорит, один способ сделать, ультраэффективная "куча" фиксированного размера:

  1. Разделите большой буфер на узлы. Размер узла должен быть, по крайней мере, sizeof (пусто*).
  2. Представьте их в виде строки вместе в отдельно-связанный-список ("бесплатный список"), с помощью первого sizeof (пусто*) байты каждого свободного узла как указатель ссылки. Выделенным узлам не будет нужен указатель ссылки, таким образом, издержки на узел будут 0.
  3. Выделите путем удаления заголовка списка и возврата его (2 загрузки, 1 хранилище).
  4. Свободный путем вставки во главе списка (1 загрузка, 2 хранилища).

Очевидно, шаг 3 также должен проверить, делает ли пустой список, и раз так набор работы, получая новый большой буфер (или сбой).

Еще более эффективный, как Greg говорят D и hazzen, должен выделить путем постепенного увеличения или постепенного уменьшения указателя (1 загрузка, 1 хранилище), и не предложить способ освободить единственный узел вообще.

Править: В обоих случаях, свободный может иметь дело со сложностью "что-либо большее, я передаю обычный диспетчер "кучи"" полезным тем, что Вы возвращаете размер в вызове к свободному. Иначе Вы посмотрели бы на любого флаг (наверху, вероятно, 4 байта за узел) или иначе поиск в некоторой записи буфера (буферов), который Вы использовали.

6
ответ дан 5 December 2019 в 10:45
поделиться

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

Raymond Chen сделал интересное сообщение, которое может помочь вдохновить Вас.:)

3
ответ дан 5 December 2019 в 10:45
поделиться

Если набор памяти будет выделен, будет использовать и будет освобождать перед хождением дальше к следующему раунду выделения, то я предложу использовать самое простое возможное средство выделения:

typedef struct _allocator {
    void* buffer;
    int start;
    int max;
} allocator;

void init_allocator(size_t size, allocator* alloc) {
    alloc->buffer = malloc(size);
    alloc->start = 0;
    alloc->max = size;
}

void* allocator_malloc(allocator* alloc, size_t amount) {
    if (alloc->max - alloc->start < 0) return NULL;
    void* mem = alloc->buffer + alloc->start;
    alloc->start += bytes;
    return mem;
}

void allocator_free(allocator* alloc) {
    alloc->start = 0;
}
0
ответ дан 5 December 2019 в 10:45
поделиться

Мне нравится ответ onebyones.

Вы могли бы также рассмотреть систему приятеля для своих наборов "кучи" фиксированного размера.

1
ответ дан 5 December 2019 в 10:45
поделиться

Я использую в основном O (1) Small Block Memory Manager (SBMM). В основном это работает следующим образом:

1) Он выделяет большие суперблоки из ОС и отслеживает начальные и конечные адреса как диапазон. Размер суперблока можно регулировать, но 1 МБ - это неплохой размер.

2) Суперблоки разбиты на блоки (также регулируемые по размеру ... 4K-64K хорошо в зависимости от вашего приложения). Каждый из этих блоков обрабатывает выделения определенного размера и сохраняет все элементы в блоке в виде односвязного списка. Когда вы выделяете суперблок, вы составляете связанный список свободных блоков.

3) Выделение элемента означает A) Проверка, есть ли блок со свободными элементами, обрабатывающими этот размер, и если нет, выделение нового блока из Суперблоки. Б) Удаление предмета из бесплатного списка блока.

4) Освобождение элемента с помощью адреса означает A) поиск суперблока, содержащего адрес (*) B) поиск блока в суперблоке (вычитание начального адреса суперблока и деление на размер блока) C) перемещение объекта обратно в список свободных предметов блока.

1275] Как я уже говорил, этот SBMM очень быстрый, поскольку он работает с производительностью O (1) (*). В реализованной мной версии я использую AtomicSList (аналогичный SLIST в Windows), так что это не только производительность O (1), но также ThreadSafe и LockFree в реализации. Вы могли бы действительно реализовать алгоритм, используя Win32 SLIST, если бы захотели.

Интересно, что алгоритм выделения блоков из суперблоков или элементов из блоков приводит к почти идентичному коду (они оба выделяются O (1) вне свободного Список).

(*) Суперблоки организованы в карту диапазона со средней производительностью O (1) (но потенциальным O (Lg N) для наихудшего случая, где N - количество суперблоков). Ширина карты диапазона зависит от приблизительного знания того, сколько памяти вам понадобится, чтобы получить производительность O (1). Если вы перестреляете, вы потратите немного памяти, но все равно получите производительность O (1). Если вы перестреляете, вы приблизитесь к производительности O (Lg N), но N соответствует количеству суперблоков, а не количеству элементов. Поскольку количество суперблоков очень мало по сравнению с количеством элементов (примерно на 20 двоичных порядков в моем коде), оно не так критично, как остальная часть распределителя.

re понадобится для получения производительности O (1). Если вы перестреляете, вы потратите немного памяти, но все равно получите производительность O (1). Если вы перестреляете, вы приблизитесь к производительности O (Lg N), но N для количества суперблоков, а не для количества элементов. Поскольку количество суперблоков очень мало по сравнению с количеством элементов (примерно на 20 двоичных порядков в моем коде), оно не так критично, как остальная часть распределителя.

re понадобится для получения производительности O (1). Если вы перестреляете, вы потратите немного памяти, но все равно получите производительность O (1). Если вы перестреляете, вы приблизитесь к производительности O (Lg N), но N соответствует количеству суперблоков, а не количеству элементов. Поскольку количество суперблоков очень мало по сравнению с количеством элементов (примерно на 20 двоичных порядков в моем коде), оно не так критично, как остальная часть распределителя.

0
ответ дан 5 December 2019 в 10:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: