Почему malloc и sbrk возвращают адрес из отдельных сегментов? - PullRequest
2 голосов
/ 22 мая 2019

Я пытаюсь понять, как происходит динамическое распределение памяти.Поэтому я подумал о реализации собственного malloc с помощью системного вызова sbrk().Мой вопрос здесь, когда я пытаюсь выделить динамическую память, sbrk () и malloc () возвращают разные адреса, а не непрерывные.

Вот мой код

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    printf("\nsbrk(0) %llu ",(unsigned long long)sbrk(0));
    printf("\nmalloc(8) %llu ",(unsigned long long)malloc(8));
    printf("\nmalloc(8) %llu ",(unsigned long long)malloc(8));
    printf("\nsbrk(8) %llu ",(unsigned long long)sbrk(8));
    printf("\nmalloc(8) %llu ",(unsigned long long)malloc(8));
    printf("\nmalloc(8) %llu ",(unsigned long long)malloc(8));  
    printf("\n");
    return 0;
}

Вывод приведенного выше кода

sbrk(0) 30306304 
malloc(8) 30306320 
malloc(8) 30306352 
sbrk(8) 30441472 
malloc(8) 30306384 
malloc(8) 30306416 

Может кто-нибудь объяснить, почему sbrk(8) не является непрерывным местоположением.

Ответы [ 2 ]

2 голосов
/ 22 мая 2019

Предполагая, что вы работаете в Linux, причина того, что память из malloc() и sbrk() имеет относительно большое различие в расположении, состоит в том, что реализация glibc malloc() использует sbrk() для получения памяти, которая функционирует таким образом.как malloc() вернуться к звонящему.Например, предположим, что начальная внутренняя реализация glibc получает 32 МБ памяти кучи через sbrk(), а память, возвращенная из malloc(), будет в этом фрагменте 32 МБ.Если вы затем используете sbrk() для получения памяти, она будет из памяти, вновь выделенной в конце этого исходного блока 32 МБ, поэтому адреса из malloc() и sbrk() будут отличаться.

Обратите внимание, что вы не можете безопасно смешивать использование malloc()calloc(), realloc() и т. Д.) И sbrk(), поскольку внутренняя реализация malloc() использует sbrk() для полученияпамять возвращается через malloc() справочной странице Linux malloc() :

Обычно malloc() выделяет память из кучи и корректирует размер кучи по мере необходимости, используя sbrk(2).При выделении блоков памяти размером более MMAP_THRESHOLD байтов реализация glibc malloc() выделяет память как частное анонимное отображение, используя mmap(2).MMAP_THRESHOLD по умолчанию составляет 128 кБ, но настраивается с помощью mallopt(3).До Linux 4.7 выделения, выполняемые с использованием mmap(2), не зависели от ограничения ресурса RLIMIT_DATA;начиная с Linux 4.7, это ограничение также применяется для распределений, выполняемых с использованием mmap(2).

Когда вы смешиваете malloc() и sbrk() в Linux для получения памяти, вы, вероятно, повредите кучу процесса.

2 голосов
/ 22 мая 2019

Стандарт не дает никакой гарантии непрерывности хранения даже для памяти, выделенной при последовательных вызовах malloc.Таким образом, различные вызовы malloc в вашем коде не должны приводить к непрерывным расположениям.

Стандарт C11 гласит:

7.22.3 Функции управления памятью

1. Порядок и непрерывность памяти, выделяемой последовательными вызовами функций aligned_alloc, calloc, malloc и realloc, не определены.

И адреса, получаемые в результате смешения вызовов malloc и sbrk, также не обязательно должны быть смежными.

...