2014-10-19 2 views
0

Вопрос может показаться немного тривиальным, я пытаюсь написать программу на C, которая просто съедает память настолько, насколько это возможно, до того, как OOM будет вызван и убьет его. Хотя я изначально использовал malloc() с memset(), я решил попробовать realloc() на этот раз. Я делаю это исключительно для обучения, так как я новичок в C.Заполнение памяти с помощью realloc

Я намерен выделить 1 МБ при каждом вызове realloc() и memset(). Когда я запускаю эту программу для выделения 20 МБ:

1) Я не понимаю, почему на выходе некоторые из этих адресов одинаковы (2-4) (5-10) & (11- 20)? Разве каждый из них не должен отличаться.

2) Является ли моя программа действительно потребляющей 20 МБ памяти? Я побежал через Valgrind и он говорит: «22,020,096 байт в 1 блоках, безусловно, потеряли в потере записи 1 из 1»

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

int main (int argc,char **argv) { 
char *ptr; 
int max = 0; 
int max_write; 
int sleep_time; 
size_t size = 1048576; 
if (argc > 1) { 
    sleep_time = (argv[2] ? atoi(argv[2]) : 2); 
    max_write = (argv[1] ? atoi(argv[1]) : 1000); 
    printf (" + To Write: %d,%d\n",max_write,sleep_time); 
} 
ptr = (char *) calloc (1,size); 
if (ptr == NULL) { 
    perror("calloc Error:"); 
} 
printf(" + Allocation: %p\n",ptr); 
do { 
    max++; 
    size += (1048576); 
    ptr = (char *) realloc (ptr,size); 
    if (ptr == NULL) { 
     perror("realloc Error:"); 
    } 
    memset(ptr,0,size); 
    printf(" + Pointer: %p/Memory: %d\n",ptr,max); 
} while (max != max_write); 
// 
return(0); 
} 



OUTPUT: 
./eatmemory 20 
+ Allocation: 0x7f2bb6b12010 
+ Pointer: 0x7f2bb6451010/Memory: 1 
+ Pointer: 0x7f2bb6150010/Memory: 2 
+ Pointer: 0x7f2bb6150010/Memory: 3 
+ Pointer: 0x7f2bb6150010/Memory: 4 
+ Pointer: 0x7f2bb5b4f010/Memory: 5 
+ Pointer: 0x7f2bb5b4f010/Memory: 6 
+ Pointer: 0x7f2bb5b4f010/Memory: 7 
+ Pointer: 0x7f2bb5b4f010/Memory: 8 
+ Pointer: 0x7f2bb5b4f010/Memory: 9 
+ Pointer: 0x7f2bb5b4f010/Memory: 10 
+ Pointer: 0x7f2bb4f4e010/Memory: 11 
+ Pointer: 0x7f2bb4f4e010/Memory: 12 
+ Pointer: 0x7f2bb4f4e010/Memory: 13 
+ Pointer: 0x7f2bb4f4e010/Memory: 14 
+ Pointer: 0x7f2bb4f4e010/Memory: 15 
+ Pointer: 0x7f2bb4f4e010/Memory: 16 
+ Pointer: 0x7f2bb4f4e010/Memory: 17 
+ Pointer: 0x7f2bb4f4e010/Memory: 18 
+ Pointer: 0x7f2bb4f4e010/Memory: 19 
+ Pointer: 0x7f2bb4f4e010/Memory: 20 

ответ

2

1) Я не понимаю, почему на выходе некоторые адреса имеют один и тот же (2-4) (5-10) & (11-20)? Если не каждый из них будет отличаться.

Как уже было сказано, realloc необязательно перемещать существующий кусок памяти, но может просто расширить его.

2) Является ли моя программа действительно потребляющей 20 МБ памяти? Я побежал через Valgrind и он говорит: «22,020,096 байт в 1 блоках, безусловно, потеряли в потере записи 1 из 1»

Это несколько зависит от конкретной реализации, но, как правило, в конечном итоге утверждая, что больше памяти, чем вы просили , Во-первых, бесплатно нужны некоторые метаданные о том, как объединить память с соседними свободными кусками. Эта информация часто находится в паре байтов прямо перед адресом, который будет возвращен alloc/realloc. Кроме того, память не может быть организована таким образом, чтобы она позволяла распределять произвольные размеры, поэтому malloc просто вернет тот, который лучше всего подходит.

2

Как говорится в documentation for realloc() и пояснено в this SO answer,

Функция может переместить блок памяти в новое место

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

Для (2), что именно вы имеете в виду «Это действительно распределение 20 МБ?» Если вы спросите realloc() за 20 МБ, он даст вам блок по крайней мере этого размера или NULL, если он не сработает. Если бы это не так, это полностью разрушило бы назначение функции.

+0

Извините, что я имел в виду, что моя программа действительно разъедала 20 МБ памяти, когда она запускается. Я не имел в виду запрос на realloc() для 20 МБ. – hmmm

+0

Поскольку вы на самом деле записываете всю память с помощью 'memset()', тогда да, вы на самом деле «едите» 20 МБ памяти. – uesp

+0

Спасибо, что имеет смысл. Последний вопрос, который у меня был, эти адреса действительно из кучи? Я думал, что они больше похожи на Stack на me.Is там в любом случае я могу проверить, если адрес принадлежит куче или стек кадров? – hmmm

1

На самом деле это нормально, если адреса повторяются.

Что это на самом деле делает:

  1. Хорошо, у меня есть указатель, который должен быть изменен на X. Сколько памяти осталось непосредственно после этого указателя?

  2. Это Y. Если Y больше X, тогда мне действительно не нужно перемещать мою память, я просто назначу еще неиспользованное пространство для своего указателя.

  3. Если Y меньше X, то здесь он не поместится. Вероятно, есть еще одна переменная, которая мешает мне расширять мой указатель на месте. Хорошо, давайте переместим его в другое место вместе со всеми данными. Помните, что мой указатель должен указывать на область памяти ..

На самом деле у меня нет вашего вопроса о 20mb. Вы беспокоитесь, что это требует немного больше? Не могу сказать, что я знаю причину, но попробую с другой итерацией и проверить, не изменились ли результаты valgrind: может быть, это вопрос некоторой оптимизации времени выполнения и предварительное распределение большего количества пространства заблаговременно? Если честно, это слепое предположение.

+0

Спасибо за объяснение! – hmmm

Смежные вопросы