Всякий раз, когда вы изучаете выделение памяти процессами, вы обычно видите это следующим образом:
Пока все хорошо.
Но тогда у вас есть системный вызов sbrk(), который позволяет программе изменять верхний предел раздела данных, и его также можно использовать, чтобы просто проверить, где это ограничение, с sbrk ( 0). Используя эту функцию, я нашел следующие шаблоны:
Шаблон 1 - Малый malloc
Я запускаю следующую программу на своей машине Linux:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int globalVar;
int main(){
int localVar;
int *ptr;
printf("localVar address (i.e., stack) = %p\n",&localVar);
printf("globalVar address (i.e., data section) = %p\n",&globalVar);
printf("Limit of data section = %p\n",sbrk(0));
ptr = malloc(sizeof(int)*1000);
printf("ptr address (should be on stack)= %p\n",&ptr);
printf("ptr points to: %p\n",ptr);
printf("Limit of data section after malloc= %p\n",sbrk(0));
return 0;
}
И вывод следующий:
localVar address (i.e., stack) = 0xbfe34058
globalVar address (i.e., data section) = 0x804a024
Limit of data section = 0x91d9000
ptr address (should be on stack)= 0xbfe3405c
ptr points to: 0x91d9008
Limit of data section after malloc= 0x91fa000
Как вы видите, выделенная область памяти была выше предела старого раздела данных, а после того, как malloc этот предел был сдвинут вверх, поэтому выделенная область находится фактически внутри нового раздела данных.
Вопрос 1. Означает ли это, что маленькие маллоки будут выделять память в разделе данных и вообще не использовать кучу?
Шаблон 2 - Большой Malloc
Если размер запрашиваемой памяти увеличен в строке 15:
ptr = malloc(sizeof(int)*100000);
вы получите следующий результат:
localVar address (i.e., stack) = 0xbf93ba68
globalVar address (i.e., data section) = 0x804a024
Limit of data section = 0x8b16000
ptr address (should be on stack)= 0xbf93ba6c
ptr points to: 0xb750b008
Limit of data section after malloc= 0x8b16000
Как вы можете видеть здесь, предел раздела данных не изменился, и вместо этого выделенная область памяти находится в середине раздела разрыва между секцией данных и стеком.
Вопрос 2: Это большой malloc, фактически использующий кучу?
Вопрос 3: Любое объяснение этого поведения? Я считаю это немного неуверенным, потому что на первом примере (small malloc) даже после того, как вы освободите выделенную память, вы все равно сможете использовать указатель и использовать эту память, не получая seg-ошибку, так как она будет внутри ваших данных раздел, и это может привести к затруднению обнаружения ошибок.
Обновление с помощью функций: Ubuntu 12.04, 32-бит, gcc версии 4.6.3, ядро Linux 3.2.0-54-generic-pae.
Обновление 2: ответ Родриго ниже решил эту тайну. Эта ссылка в Википедии также помогла.