C/C++ memory management – realloc and mremap

English version below

Прочитал новость, что mremap в Linux 3.2 ускорили, а точнее улучшили работу с TLB. Какие программы это ускорит? В каких случаях вообще используется realloc?

К примеру динамический буффер в куче. Когда мы добаваляем в него данных, и он автоматически расширяется, при этом данные в нем хранятся непрерывно. Например std::vector. Однако std::vector, как и все контейнеры STL, и даже контейнеры сторонних библиотек используют std::allocator для управления памятью. std::allocator имеет только две функции для управления памятью allocate и deallocate.
Все просто, однако мы не можем использовать опимизированную realloc. Таким образом когда мы в std::vector добавим очередной элемент, и это потребует расширения std::vector, мы вызовем allocator.allocate() с новым размером, расчитанным по определенным правилам, потом скопируем все элементы в новое место и вызовем allocator.deallocate() для сторого куска. Плюс вызов конструкторов, деструкторов если необходимо. Таким образом все STL контейнеры не могут использовать realloc, потому что завязаны на std::allocator. Даже больше, в С++ память выделяется с помощью new, delete и идеологически нет возможности сделать realloc, кроме как через new, copy, delete. С одной стороны это упрощает C++, но с другой мы теряем часть возможностей доступных уровнем ниже.
А теперь вопрос, зачем нужно хранить данные непрерывно? Есть C функции, которые работают с непрерыными кусками памяти (binary_search, строковые,…), однако ядро имеет writev/readv, т.е. работать с фрагментированными кусками памяти. Можно иметь свой контейнер, который будет хранить фрагментированно и binary_search, строковые функции которые будут рабоать с таким контейнером.
Быстрый поиск по boost и я не нашел подобного контейнера. Вопрос о накладных расходах хранения данных фрагментированно – понятно, что хранить каждый байт в своем фрагменте и выводить через writev() и по памяти и по CPU накладнее. Будет время, сделаю тесты по скорости динамических буферов с хранением непрерывно и фрагментированно.
К слову coreutils и libevent используют realloc в некоторых местах для работы с динамическими буферами, nginx нет.


Read the news about increseasing speed of mremap in Linux 3.2, specifically work with TLB. What pragramms will benefit from this? In which cases is realloc used? I.e. dynamic buffer on the
heap. When we add data to it, it increases automaticaly, meanwhile data is stored continiously. For example, std::cector. But std::vector, as all STL containers, and even third-party libraries
containers use std::allocator for memory management. std::allocator has only two function for memory management allocate and deallocate. That’s simple, but we are not able to use optimised realloc.
Thus when we add new element to std::vector, and it will be needed to expand std::vector, we will call allocator.allocate() with new size, computed with some defined rules, then copy all elements in new place and call allocator.deallocate() for old chunk. Plus calling constructors, destructors if necessary. So all STL containers can’t use realloc, because are linked with std::allocator. Even more, all memory in C++ memory is managed with new and delete and ideologically there is no way to do realloc, except new, copy, delete. One the one side it makes C++ easier, but on the other we loose some functionality, available on lower level.
And now the question is – why we need to store data continiously? There are С functions, that work with continiously allocated data (binary_search, string functions, …), but kernel has writev/readv, and thus can work with fragmented memory. We can have our own container, that will store data fragmented and our binary_search, string functions that will work with such container. Fast search in boost, but I didn’t find any such container. The question is about overhead with storing data fragmented. It’s clear, that storing single byte in it’s own chunk and output it with writev() will have a lot of CPU and memory overhead. Sometime I’ll write test comparing storing data contitiously and fragmented.
By the way coreutils and libevent use realloc in some places to work with dynamic buffers, nginx do not.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s