Cj *_*sen 10 c memory heap-fragmentation
在我的课上,我们有一个作业,其中一个问题是:
C中的内存碎片:设计,实现并运行执行以下操作的C程序:它为3m数组的序列分配内存,每个数组大小为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");
};
Run Code Online (Sandbox Code Playgroud)
我已经通过几种不同的方式对此进行了更改,但我看到的一致性是,当我最初为3*m*500000元素阵列分配内存时,它会耗尽所有可用的主内存.但是当我告诉它释放它们时,内存不会释放回操作系统,因此当它分配m*700000元素数组时,它会在页面文件(交换内存)中执行它,因此它实际上并不显示内存碎片.
上面的代码运行1000次并取平均值,需要相当长的时间.第一个序列平均值为2.06913秒,第二个序列值为0.67594秒.对我来说,第二个序列应该花费更长的时间来显示碎片是如何工作的,但由于使用了交换,因此不会发生这种情况.有没有办法解决这个问题,还是我的假设错了?
我会问教授星期一我有什么,但在那之前我会得到任何帮助.
许多 libc 实现(我认为包括 glibc)在调用 时不会将内存释放回操作系统free(),而是保留它,以便您可以在下一次分配时使用它而无需系统调用。此外,由于现代分页和虚拟内存策略的复杂性,您永远无法确定任何内容在物理内存中的位置,这使得几乎不可能故意对其进行碎片化(即使它是碎片化的)。你必须记住,所有虚拟内存和所有物理内存都是不同的东西。
(以下是针对 Linux 编写的,但可能适用于 Windows 和 OSX)
当您的程序进行第一次分配时,假设操作系统有足够的物理内存来挤入所有页面。它们在物理内存中并不都是彼此相邻的——它们分散在任何可能的地方。然后操作系统修改页表以创建一组连续的虚拟地址,这些地址引用内存中分散的页面。但事情是这样的——因为你并没有真正使用你分配的第一个内存,所以它成为交换的一个很好的候选者。因此,当您进行下一次分配时,内存不足的操作系统可能会交换其中一些页面,为新页面腾出空间。因此,您实际上测量的是磁盘速度以及操作系统分页机制的效率,而不是碎片。
请记住,一组连续的虚拟地址在实践中(甚至在内存中)几乎从不物理上连续。