даже если забыть о прослойках в libc и kernel.org, остается вопрос что делает аргумент size в вызове munmap.
Семантика у них чуток разная, только и всего. malloc(3) не умеет 'частично' освободить память, только весь выделенный ранее блок целиком. munmap(2) может.
А я так глубоко и не копал - работает, ну и ладно. Я всегда думал, что при выделении памяти при помощи malloc/calloc ядро предоставляет первый свободный блок памяти подходящего размера, и само же «для себя» делает пометку, что этот блок выделен такому-то процессу. Если процесс дохнет, не успев сделать free, ядро память освобождает.
А по-вашему выходит, что каждый раз, когда я в программе, динамически выделяющей память, нажму ctrl+C до free, у меня будет происходить утечка памяти... Фигня какая-то получается.
А по-вашему выходит, что каждый раз, когда я в программе, динамически выделяющей память, нажму ctrl+C до free, у меня будет происходить утечка памяти... Фигня какая-то получается.
По-нашему получается, что ядро по запросу процесса может добавить в адресное пространство ещё страничек памяти (обычно, гранулярностью по 4096 байт, но бывает и больше, и меньше), либо отрезать их. Как там процесс организует работу с памятью в рамках своего личного адресного пространство (АП) - ядро не волнует. Соответственно, в программах используется какой-либо менеджер (аллокатор) для управления пулом доступной памяти. Такой менеджер может выделить программе (заметь, из её же АП) блок памяти любого размера, от 1 байта до практического лимита, и пометит у себя в маленькой чёрной книжечке, что, де, вот по такому адресу у нас выделено столько-то байт. Детали реализации книжечки, т.е. как менеджер хранит информацию о выделенной и свободной памяти, нигде не оговариваются.
У ядра есть примерно такой же механизм, ибо оно должно знать, где и сколько есть физической памяти, кому она выделена, а также как «сшито» виртуальное АП разных процессов. Это примерно в 100500 раз сложнее, чем банальный malloc/free в юзерспейсе.
> Все известные мне имплементации хранят перед собственно блоком.
Значит не все ты видел. Большинство реализаций создают отдельные блоки на каждый из малых размеров, и, соответственно, на выделение 100 раз по int они не будут тратить 200*sizeof(int). То есть, информация о размере выделенного куска вычисляется из его адреса.
> Я всегда думал, что при выделении памяти при помощи malloc/calloc ядро предоставляет первый свободный блок памяти подходящего размера, и само же «для себя» делает пометку, что этот блок выделен такому-то процессу.
Ядро ничем таким не занимается. Ядро обслуживает вызов mmap(), которым malloc из libc себе отгрызает сразу большие куски, внутри которых уже и резвится.
Есть системный вызов sysbrk, которые устанавливает размер heap. Все просто.
Менеджер памяти в библиотеке С хранит размер или в отдельном блоке, или в структуре ПЕРЕД адресом, который возвращает malloc. Или он хранит перед этим адресом адрес, где он хранит размер. И конечно может быть еще какая нибудь реализация, но все в этом духе. Можно пощупать, прочитав данные перед ним. Ничего плохого не случится скорее всего, segfault случается при чтении из адресов, которых нету в адресном пространстве процессе. Адресное пространство процесса состоит из нескольких частей (в Intel по крайней мере)
- Сегмент кода (из вашего бинарника)
- Инициализированные данные (в вашем бинарнике хранятся)
- Неинициализированный данные (в бинаринке только размер, выделятся системой при запуске)
- Куча (задается с помощью sysbrk, растет вверх)
- Стек (задается уменьшением esp, растет вниз)
Поправьте если что не так.
Вызовы malloc/free размещают кусочками ваши указатели в куче, меняя ее размер по мере надобности.