C++-linux内存分配
在《Linux程序设计(第四版)》第七章中,开头给出了一段代码,功能是分配大小为机器物理内存容量的2倍的内存,并且可以分配成功。原因是因为当物理内存耗尽之后,会开始使用所谓的交换空间。代码如下
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 #define A_MEGABYTE (1024 * 1024)
6 #define PHY_MEM_MEGS (1024 * 4)//我的机器内存是4GB
7
8 int main()
9 {
10 char *some_memory;
11 size_t size_to_allocate = A_MEGABYTE;
12 int meg_obtained = 0;
13
14 while(meg_obtained < PHY_MEM_MEGS * 2)
15 {
16 some_memory = (char*)malloc(size_to_allocate);
17 if(some_memory != NULL)
18 {
19 meg_obtained++;
20 sprintf(some_memory,"Hello world");
21 printf("%s - now allocated %d Megabytesn",some_memory,meg_obtained);
22 }
23 else
24 exit(EXIT_FAILURE);
25 }
26
27 exit(EXIT_SUCCESS);
28 }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
内存限制不仅仅是物理内存+swap。
还有地址位数的限制,对于32bit系统,地址是用unsigned int 表示,最大是4G,内核1G左右,用户空间就是3G左右,是地址位数限制了程序的虚拟地址空间到4GB的。
我的是64bit系统,运行你的程序,到8192MB,也就是到8G。
你用 'cat /proc/cpuinfo'看下,我的'address sizes'显示是36bit physical,48bit virtual,也就是CPU支持物理内存最大是64GB,虚拟地址256TB,而我的内存是3.8G,交换空间4.7G,总共8.5G(通过系统监视器看的)。CPU支持这么多内存,但是我的配置只有3.8G物理内存,而程序虚拟内存除了可以映射到物理内存,还可以映射到硬盘的交换空间,所以程序的最大虚拟空间是8.5G=min(8.5G,256TB)。
而用malloc分配的内存是程序的heap空间,也就是8.5G减掉,内核代码及数据,栈空间,该程序所链接的共享库的空间,还有代码段,数据段的空间,还有其他程序所占用的物理内存。
这差不多就是8G了吧。
如果你用32位操作系统,相当于只使用IA32指令,寄存器都是32位的,由于访存指令的内存地址很多是存在寄存器的,那么对于这些指令,最多只能访问4G的虚拟地址空间。
当然32位操作系统后来变NB了,通过所谓PAE技术,使得程序可以使用那36根地址线(没有PAE,只能使用32根,即使支持PAE的32位的CPU有36根地址线,没有PAE,相当于浪费了这些CPU的4根地址线),也就是说,虚拟地址还是32位,可以映射到超过4G的物理内存,那么对于单个应用程序来说,最大可使用的内存还是4GB,不过传闻还有AWE(address windows extension)技术,使得单个程序在开了PAE的32位操作系统上可以使用大于4GB的内存,我暂时没时间管这东西,理解这些东西也只有学术上的意义,现在新出的CPU都是64位的了,操作系统也向64位迈进了,作为小小码农的我们干嘛还要去管这些老掉牙的东西呢?
Linux里的内存是虚拟内存,整个物理内存被分为内核空间和用户空间两部分,对于4G内存,一般是内核1G,用户空间3G。
进程是运行在虚拟内存上的,虚拟内存是通过页面来映射的,这样是得每个进程的空间都能够达到整个用户空间。因此,你的代码最多能分配3000多M的内存。
好吧,我来写一下。
可用内存 = 物理内存 + swap
至于具体的内存使用,可以参照深入理解linux内核的第8章。
Linux的虚拟地址空间也为0~4G。Linux内核将虚拟的4G字节的空间分为两部分。将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为"内核空间"。将较低的3G字节(从虚拟地址 0x00000000到0xBFFFFFFF),供各个进程使用,称为"用户空间"。
其中,很重要的一点是虚拟地址空间,并不是实际的地址空间。进程地址空间是用多少分配多少,4G仅仅是最大限额而已。往往,一个进程的地址空间总是小于4G的,你可以通过查看/proc/pid/maps文件来获悉某个具体进程的地址空间。但进程的地址空间并不对应实际的物理页,Linux采用 Lazy的机制来分配实际的物理页(“Demand paging"和"和写时复制(Copy On Write)的技术"),从而提高实际内存的使用率。即每个虚拟内存页并不一定对应于物理页。虚拟页和物理页的对应是通过映射的机制来实现的,即通过页表进行映射到实际的物理页。因为每个进程都有自己的页表,因此可以保证不同进程的相同虚拟地址可以映射到不同的物理页,从而为不同的进程都可以同时拥有4G的虚拟地址空间提供了可能。
楼主混淆的虚拟地址和物理地址的概念。
应用程序运行在虚地址空间,32位操作系统虚拟地址空间为4G,这个跟你的内存大小没有直接关系(内存大小会影响系统运行性能),虚实地址的映射由OS来完成,这个对应用层的程序员来说是透明的。
32位的Linux会将高地址的1G作为内核空间,剩余的3G给用户空间。
而由于进程一部分地址空间用于存放程序的.text以及data段,所以实际上留给堆的空间一般会比3G要少,下图就是一个Linux进程地址分布空间。
32位的CPU下,程序使用的空间也是可以超过4GB,这里说的是物理地址扩展(PAE:Physical Address Extension),需要CPU和OS的支持才行。windows下采用地址窗口扩展(AWE:Address Windowing Extensions)的机制实现。
参考链接:32位的CPU下,程序使用的空间能不能超过4GB?
你的问题本身有问题,能分配多大内存空间(此为虚拟内存)和你机器内存(此为物理内存)是不是4G没有关系。
我猜你用的32位机,对于32位机器,虚拟内存大小为2^32=4G
Linux下用户空间占3G,内核占1G,所以你最多分配3G左右的空间。
Windows下用户空间默认占2G,内核占2G(这个数值可以通过修改boot.ini文件来调整)
参考自《程序员的自我修养——链接、装载与库》