Целенаправленно тратить всю основную память на изучение фрагментации
В моем классе у нас есть задание, и один из вопросов гласит:
Фрагментация памяти в C: спроектировать, реализовать и запустить C-программу, которая выполняет следующие действия: она выделяет память для последовательности из 3-х массивов размером 500000 элементов каждый; то он освобождает все массивы с четными номерами и выделяет последовательность из m массивов размером 700000 элементов каждый. Измерьте количество времени, которое требуется вашей программе для распределения первой последовательности и для второй последовательности. Выберите m, чтобы вы исчерпали всю основную память, доступную вашей программе. Объясните свои тайминги
Моя реализация этого заключается в следующем:
#include <iostream>
#include <time.h>
#include <algorithm>
void main(){
clock_t begin1, stop1, begin2, stop2;
double tdif = 0, tdif2 = 0;
for(int k=0;k<1000;k++){
double dif, dif2;
const int m = 50000;
begin1 = clock();
printf("Step One\n");
int *container[3*m];
for(int i=0;i<(3*m);i++)
{
int *tmpAry = (int *)malloc(500000*sizeof(int));
container[i] = tmpAry;
}
stop1 = clock();
printf("Step Two\n");
for(int i=0;i<(3*m);i+=2)
{
free(container[i]);
}
begin2 = clock();
printf("Step Three\n");
int *container2[m];
for(int i=0;i<m;i++)
{
int *tmpAry = (int *)malloc(700000*sizeof(int));
container2[i] = tmpAry;
}
stop2 = clock();
dif = (stop1 - begin1)/1000.00;
dif2 = (stop2 - begin2)/1000.00;
tdif+=dif;
tdif/=2;
tdif2+=dif2;
tdif2/=2;
}
printf("To Allocate the first array it took: %.5f\n",tdif);
printf("To Allocate the second array it took: %.5f\n",tdif2);
system("pause");
};
Я изменил это несколько разных способов, но консистенции, которые я вижу, это то, что, когда я изначально выделяю память для массивов элементов размером 3 * м * 500000, он использует всю доступную основную память. Но затем, когда я говорю, чтобы освободить их, память не возвращается обратно в ОС, поэтому, когда она идет на выделение массивов элементов m * 700000, она делает это в файле страницы (своп-память), поэтому на самом деле она не отображает фрагментацию памяти.
Приведенный выше код работает в 1000 раз и усредняет его, это занимает довольно много времени. Первая средняя последовательность составила 2.06913 секунды, а вторая - 0.67594 секунды. Для меня вторая последовательность должна занимать больше времени, чтобы показать, как работает фрагментация, но из-за использования подкачки это не происходит. Есть ли способ обойти это или я ошибаюсь в своем предположении?
Я спрошу профессора о том, что у меня есть в понедельник, но до тех пор любая помощь будет оценена.
Ответы
Ответ 1
Многие реализации libc (я думаю, что glibc включен) не возвращают память обратно в ОС при вызове free()
, но сохраняйте ее, чтобы вы могли использовать ее при следующем распределении без syscall. Кроме того, из-за сложности современных улочек страниц и виртуальной памяти вы никогда не можете быть уверены, где что-либо находится в физической памяти, что делает его практически невозможным для намеренного фрагментации (даже если он фрагментирован). Вы должны помнить, что вся виртуальная память и вся физическая память - это разные звери.
(Ниже приведено для Linux, но, вероятно, применимо к Windows и OSX)
Когда ваша программа делает первые выделения, скажем, что для операционной системы достаточно физической памяти, чтобы сжать все страницы. Они не все рядом друг с другом в физической памяти - они разбросаны везде, где они могут быть. Затем ОС изменяет таблицу страниц, чтобы создать набор непрерывных виртуальных адресов, которые относятся к разбросанным страницам в памяти. Но вот что - потому что вы действительно не используете первую память, которую вы выделяете, она становится действительно хорошим кандидатом для замены. Итак, когда вы приступите к следующим распределениям, ОС, заканчивающийся из памяти, вероятно, поменяет некоторые из этих страниц, чтобы освободить место для новых. Из-за этого вы фактически измеряете скорость диска и эффективность механизма поискового вызова операционных систем, а не фрагментацию.
Помните, что набор непрерывных виртуальных адресов практически никогда не является физически непрерывным на практике (или даже в памяти).