Свободная память с явным размером - PullRequest
6 голосов
/ 09 октября 2019

Я ищу malloc / free -подобные API в основных ОС, которые позволяют мне указывать явный размер как при выделении, так и при удалении. Что я надеюсь получить от этого, так это то, что среда выполнения может тратить меньше памяти на бухгалтерию, когда выделенный размер уже доступен в программе.

В случае, например, окон, которые я нашел только free(), _aligned_free() и _freea(), ни один из которых не принимает второй аргумент для размера.

Ответы [ 3 ]

3 голосов
/ 09 октября 2019

Я ищу malloc / free-like API в основных ОС, которые позволяют мне указывать явный размер как при выделении, так и при удалении.

Я не в курселюбого.

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

Эта идея, безусловно, может работать, но есть несколько недостатков:

  1. вам необходимо разделить области выделения между объектами, выделенный размер которых отслеживается вызывающей стороной, и объектами, в которых распределитель все еще остается. необходимо записать это сам.

    Это увеличивает сложность и потенциально фрагментацию памяти.

  2. Вы должны выделить точно размер, который запрашивает программа.

    То есть нормальный распределитель мог бы решить вернуть 96-байтовый блок для 64-байтового запроса, потому что он только что был освобожден, перегрелся в кеше и разделил и повторно скомбинировал chunks меньше 64 байт не считается стоящим.

    Ваш распределитель не может этого сделать, в общем случае (он ограничен округлением до следующего выровненного размера чанка).


Конечно, существует множество специализированных распределителей, которые явно управляют этими компромиссами.

Использование или запись этих данных - совершенно нормальная вещь, когда распределитель общего назначения не подходитдля ваших моделей распределения. Но они обычно не предоставляются языком или ОС, потому что они не общего назначения. Они предоставляются библиотеками (или вами).

Примеры:

  1. Вы выделяете и освобождаете множество объектов с ранее известным фиксированным размером.

    Напишите для них распределитель пула объектов. Ему не нужно отслеживать размер выделения, потому что он всегда один и тот же (часто это параметр шаблона). Вам также не нужно явно отслеживать его в вашем коде, потому что это подразумевается типом.

  2. Распределение переменных размеров тривиальных объектов, имеющих одинаковое время жизни (например, множествобуферы символов).

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

NB. Если вы решите интегрировать свой распределитель с использованием перегрузок new / delete (и думаете, что он получит выгоду от явного параметра размера), вы абсолютно можете использовать те, на которые указывает Максим, со следующим предупреждением:

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

0 голосов
/ 09 октября 2019

Если вы ищете более быструю malloc & free, есть новая (13 февраля 2019 г.) замена для систем, которые уже поддерживают аппаратный модуль управления памятью MMU. Большинство компьютеров это делают, большинство микроконтроллеров этого не делают.

Есть статья и исследование, в которых показано, что она уменьшает память Firefox на 16% и Redis на 39%.

Она называется Mesh, Сетчатое динамическое распределение памяти

0 голосов
/ 09 октября 2019

operator delete семья принимает размер. См. operator delete, operator delete[]:

void operator delete  (void* ptr, std::size_t sz) noexcept;
void operator delete[](void* ptr, std::size_t sz) noexcept;
void operator delete  (void* ptr, std::size_t sz, std::align_val_t al) noexcept;
void operator delete[](void* ptr, std::size_t sz, std::align_val_t al) noexcept;

Вызывается вместо void operator delete(void* ptr) noexcept и void operator delete[](void* ptr) noexcept;, если предусмотрена пользовательская замена.

Благодаря компилятору, предоставившему вам размер.

...