在《C++程序设计教程》P184有一道课后练习题,要求编写程序,测试堆内存容量.我随手写了一个小程序,在Linux和Windows下均运行成功,下面是主要代码:
#define Testspace 10000//Testspace为每次在堆内开辟的空间
void main()
{
int *
pointer;
unsigned
long int counter=0,HeapCapacity=0;//
do
{
pointer=(int *)malloc(Testspace*sizeof(int));//int 占4个字节
counter=counter+1;
printf("------counter=%lu\n",counter);//为了验证共开辟了多少次堆
}
while(pointer!=NULL);
HeapCapacity=counter*Testspace*4/1024/1024;//得出的单位是兆M,若要得到G,
//还要再/1024
printf("\nHeapCapacity
is %luM\n",HeapCapacity);
if(pointer==NULL)
exit
(1);
free(pointer);
}
运行后,对Testspace采用不同的值,得到的结果几乎相同。Testspace=10000,
HeapCapacity=3064M;Testspace=1000,HeapCapacity=3056M;Testspace=5000,Heapcapacity=3063M;Testspace=20000,HeapCapacity=3065M;单位是兆,换成G的话,大概都是3G左右。疑问产生了,我分别是在RAM=1G的笔记本和RAM=2G的台式机上运行,为什么得到的答案一样,堆不是内存里的一个空间么?为什么得到的结果会大于物理内存。
这就需要从虚拟内存说起。
其实,我们使用的内存,根本就不是物理内存,如果我们在程序中都引用了绝对物理地址,那程序就会崩溃,我们希望每个程序都使用一套私有的本地地址来进行内存寻址,把物理地址暴露给进程会带来严重问题,谁写程序时会接着别人剩下的地址写呢?听起来太荒唐了。那么一个更好的办法是创造一个新的内存抽象:地址空间。虚拟内存的基本思想是:每个程序拥有自己的地址空间,每个空间被分割成多个块,每一块称作一页或页面,每一页有连续的地址范围,这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行,接下来就会涉及到很多操作系统书上讲到的置换与映射问题,此处不再论述。
每个Linux进程都有一个地址空间,逻辑上有3段组成:代码,数据和堆栈段。32位机器上每个Linux进程通常有3GB的虚拟地址空间。Windows中有一个极端复杂的虚拟内存系统,对以
x86机器,虚拟地址是32位的,因此每个进程有4G虚拟地址空间,其中用户态进程的虚拟地址大小为2G,另外的2G或1G为内核进程使用。最后,Linux和Windows下对应的虚拟内存文件是:Swap分区和pagefile.sys。