Почему ранее выделенная память недоступна после сбоя перераспределения?

Мне необходимо выделить всю память, доступную для процесса, чтобы выполнить тест системного сервиса. Тест (среди прочего) требует исчерпания всех доступных ресурсов, попытки вызова и проверки конкретного результата.

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

Код, который я написал, выглядит следующим образом (отладочные отпечатки также включены)

#include <stdio.h>
#include <malloc.h>
int main(void)
{
char*       X;
char*       lastgood = NULL;
char*       toalloc = NULL;
unsigned int    top = 1;
unsigned int    bottom = 1;
unsigned int    middle;
do
{
bottom = top;
lastgood = toalloc;
top = bottom*2;
printf("lastgood = %p\ntoalloc = %p\n", lastgood, toalloc);
if (lastgood != NULL)
printf("*lastgood = %i\n", *lastgood);
toalloc = realloc(toalloc, top);
printf("lastgood = %p\ntoalloc = %p\n", lastgood, toalloc);
if (toalloc == NULL && lastgood != NULL)
printf("*lastgood = %i\n", *lastgood);  //segfault happens here
}while(toalloc != NULL);
do
{
if (toalloc != NULL) lastgood = toalloc;
else toalloc = lastgood;
middle = bottom+(top - bottom)/2;
toalloc = realloc(toalloc, middle);
if (toalloc == NULL) top = middle;
else bottom = middle;
}while(top - bottom > 1);
if (toalloc != NULL) lastgood = toalloc;
X = lastgood;
//make a call that attempts to get more memory
free(X);
}

Согласно man-странице realloc, realloc не уничтожает предыдущий адрес, если возвращает null. Тем не менее, этот код приводит к segfault, когда он пытается напечатать lastgood после того, как toalloc получает NULL от realloc. Почему это происходит, и есть ли лучший способ просто получить точное количество нераспределенной памяти?

Я запускаю его на glibc, на Ubuntu с ядром 3.11.x

0

Решение

Вы не проверяете значение top для переполнения. Вот что происходит с его значением:

2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
1073741824
2147483648
0

Незадолго до последнего realloc(), новое значение вершины снова равно 0 (на самом деле 2^32 но это не умещается в 32 бита), что, по-видимому, приводит к фактическому освобождению блока памяти.


Попытка выделить максимально непрерывный блок не очень хорошая идея. Карта памяти, видимая пользовательским процессом, имеет некоторый блок, уже выделенный для общих библиотек, а также фактический код и данные текущего процесса. Если вы не хотите знать максимальный непрерывный блок памяти, который вы можете выделить, способ состоит в том, чтобы выделить как можно больше в одном блоке. Когда вы достигнете этого, сделайте то же самое с другим указателем и продолжайте делать это до тех пор, пока у вас не закончится память. Примите во внимание, что в 64-битных системах вы не получаете всю доступную память всего за одну malloc()/realloc(), Как я только что видел, malloc() в 64-битных системах выделяют до 4GB памяти в одном вызове, даже если вы можете выдать несколько mallocs() и до сих пор добиваются успеха на каждом из них.

Визуальное отображение карты памяти пользовательского процесса в 32-битной системе Linux описано в ответе, который я дал несколько дней назад:
Соответствует ли пространство ядра пользовательскому пространству в Linux x86?

Я придумал эту программу, чтобы «съесть» всю память, которая может:

#include <stdio.h>
#include <malloc.h>

typedef struct slist
{
char *p;
struct slist *next;
} TList;

int main(void)
{
size_t nbytes;
size_t totalbytes = 0;
int i = 0;
TList *list = NULL, *node;

node = malloc (sizeof *node);
while (node)
{
node->next = list;
list = node;
nbytes = -1; /* can I actually do this? */
node->p  = malloc(nbytes);
while (nbytes && !node->p)
{
nbytes/=2;
node->p = malloc(nbytes);
}
totalbytes += nbytes + sizeof *node;
if (nbytes==0)
break;
i++;
printf ("%8d", i);
}
printf ("\nBlocks allocated: %d. Memory used: %f GB\n",
i, totalbytes/(1024*1048576.0));
return 0;
}

Выполнение выдает эти значения в 32-битной системе Linux:

 1       2       3       4       5       6       7       8       9      10
11      12      13      14      15      16      17      18      19      20
21      22      23      24      25      26      27      28      29      30
31      32      33      34      35      36      37      38      39      40
41      42      43      44      45      46      47      48      49      50
51      52      53
Blocks allocated: 53. Memory used: 2.998220 GB

Очень близко к пределу 3 ГБ в 32-битных системах Linux. В 64-битной системе Linux я достиг 30000 блоки 4GB каждый и до сих пор считает. Я действительно не знаю, может ли Linux выделить столько памяти или это моя ошибка. В соответствии с этот, максимальное виртуальное адресное пространство составляет 128 ТБ (это было бы 32768 4GB блоки)


ОБНОВЛЕНИЕ: на самом деле, так оно и есть. Я оставил запуск этой программы на 64-битном компьютере, а после 110074 успешно распределенные блоки, общий объем выделенной памяти был 131071.578884 GB , каждый malloc() смог выделить столько, сколько 4 GB за операцию, но при достижении 115256 GBначал выделять до 2 GBзатем, когда он достиг 123164 GB выделил, начал выделять до 1GB в malloc(), Прогрессия асинхронно имеет тенденцию к 131072 GB, но на самом деле это останавливается немного раньше, 131071.578884 GB потому что сам процесс, его данные и общие библиотеки, использует несколько КБ памяти.

введите описание изображения здесь

5

Другие решения

Я думаю getrlimit() это ответ на ваш новый вопрос. Вот справочная страница http://linux.die.net/man/2/getrlimit

Вы, вероятно, заинтересованы в RLIMIT_STACK, Пожалуйста, проверьте страницу руководства.

1

Первая часть заменена на следующую.

char *p;
size_t size = SIZE_MAX;//SIZE_MAX : #include <stdint.h>
do{
p = malloc(size);
size >>= 1;
}while(p==NULL);
0
По вопросам рекламы [email protected]