zoukankan      html  css  js  c++  java
  • 32位模式下C/C++程序可用最大内存

    关于32位程序申请大内存问题(1.6G). 我在win7 64系统上面测试
    Visual studio 10

    [c] view plain copy
     
    1. int* Test=new int[1024*1024*200];  
    2.   
    3. int* Test2=new int[1024*1024*200];  


    申请1.6G内存.
    抛出:
    cpptest2.exe 中的 0x770e15ee 处有未经处理的异常:

     Microsoft C++ 异常: 内存位置 0x0044f660 处的 std::bad_alloc。

    这只是一个简单的测试 . 我做三维仿真.. 内存要用到2G-4G左右.. 如何在64位系统 32位程序申请到大内存啊..


    ------解决方案--------------------------------------------------------
    32位程序不可能申请大于4G的内存,linux在X86系统下,理论上用户态可以申请3G内存(有1G的地址空间留给内核),内核态可以申请4G内存,windows你需要查一查其系统规范。
    ------解决方案--------------------------------------------------------
    用文件读写模拟内存读写是在32位操作系统下使用超过4G内存的不二法门。

    参考_lseeki64

    在windows 32位操作系统中,每一个进程能使用到的最大空间(包含操作系统使用的内核模式地址空间)为4GB , 在通常情况下操作系统会分配2GB内存给进程使用,另外2GB内存为操作系统保留, 例如安装了64GB内存,在服务器上安装了SQL / Exchange / ISA / IIS ..... ,那么每个进程(SQL /Exchange / ISA /III ) 能用到的最大空间通常为2GB ,但是微软允许通过在boot.ini 中加入/3GB参数,将操作系统保留的2GB内存减少到1GB,从而将分配给进程的内存提高到3GB 。

    如果希望应用程序能使用更大的内存,他就需要将他的操作系统和应用程序迁移到64 位平台上。


    具体说明可以看下面的文章

    http://msdn2.microsoft.com/zh-cn/library/ms189334.aspx


    进程地址空间   

    所有 32 位应用程序都有 4 GB 的进程地址空间(32 位地址最多可以映射 4 GB 的内存)。对于 Microsoft Windows 操作系统,应用程序可以访问 2 GB 的进程地址空间,称为用户模式虚拟地址空间。应用程序拥有的所有线程都共享同一个用户模式虚拟地址空间。其余 2 GB 为操作系统保留(也称为内核模式地址空间)。所有操作系统版本(从 Windows 2000 Server 开始,包括 Windows Server 2003)都有一个 boot.ini 开关,可以为应用程序提供访问 3 GB 的进程地址空间的权限,从而将内核模式地址空间限定为 1 GB。

    地址窗口化扩展插件 (AWE) 通过允许访问尽可能多的操作系统支持物理内存来扩展 32 位应用程序的功能。AWE 可以将最大内存容量 64 GB 的一部分映射到用户地址空间来实现此功能。应用程序缓冲池和 AWE 映射内存之间的映射通过操作 Windows 虚拟内存表来完成。
    为了支持 3 GB 的用户模式进程空间,必须将 /3gb 参数添加到 boot.ini 文件中并重新启动计算机,从而使 /3gb 参数生效。设置此参数后,用户应用程序线程可以寻址 3 GB 的进程地址空间,而为操作系统保留 1 GB 的进程地址空间。
    注意:  
    如果计算机上有 16 GB 以上的可用物理内存,操作系统需要 2 GB 的进程地址空间供系统使用,因此只能支持 2 GB 的用户模式地址空间。为了让 AWE 能够使用 16 GB 以上的内存,应确保 boot.ini 文件中没有 /3gb 参数。否则,操作系统就不能寻址 16 GB 以上的内存。

    .Net 应用程序如何在32位操作系统下申请超过2G的内存

    AWE方式虽然可以访问超过2G的内存,但其本身也有一些问题,首先必须要锁定内存,其次需要自己写内存管理程序来管理这些内存,.net framework 无法在AWE 扩展的内存中创建托管堆。其实很多应用只是想申请比2G稍多一些的内存,最简单的方法还是采用/3GB开关来实现。本文将讲述如何利用 /3GB开关来让32位操作系统下.net 应用程序申请超过2GB的内存。

    首先简单说一下这个 /3GB 开关 (知道的可以不看)

    默认情况下,Windows 可以对总计 4 千兆字节 (GB) 的虚拟地址空间进行寻址。默认情况下,此地址空间中的 2 GB 为内核(操作系统)保留,另外 2 GB 是为用户模式程序保留的。当你将 /3GB 开关放入操作系统的 Boot.ini 文件中时,你就重新分配了虚拟地址空间,给用户模式程序提供 3 GB 的空间,同时将内核限制为 1 GB。

    设置办法:C:oot.ini 文件做如下修改:

    [boot loader]
    timeout=30
    default=multi(0)disk(0)rdisk(0)partition(2)WINNT
    [operating systems]
    multi(0)disk(0)rdisk(0)partition(2)WINNT="????" /3GB
    

    如下操作系统可以支持 /3GB 开关

    Windows XP Professional
    Windows Server 2003
    Windows Server 2003, Enterprise Edition
    Windows Server 2003, Datacenter Edition
    Windows 2000 Advanced Server
    Windows 2000 Datacenter Server
    Windows NT Server 4.0, Enterprise Edition

    Windows VISTA , Windows 7 和 Windows server 2008 也支持这个开关

    详见

    http://www.microsoft.com/whdc/system/platform/server/PAE/PAEmem.mspx

    设置完后重新启动系统,这时应用程序就可以申请超过3G的内存了。一切好像到这里就该结束了,然而并非如此。

    当我运行我在.net framework 下做的测试程序时,我发现3GB开关打开后,这个测试程序依然无法申请超过2G的内存,内存申请到1.5G以上时就无法再分配内存了。

    查找资料后我发现,操作系统在支持/3GB参数后应用程序也要做相应的修改,告诉操作系统可以按照/3GB方式运行才行,我想这很可能是出于对应用程序兼容性方面的考虑。

    为了告知操作系统这个应用程序可以支持/3GB方式,我们需要往exe 文件头中添加一个 IMAGE_FILE_LARGE_ADDRESS_AWARE 标志。添加的方式很简单:

    在你的系统的 Program FilesMicrosoft Visual Studio 8VCin 目录下找到 editbin 这个可执行文件,在命令行下执行:

    editbin /LARGEADDRESSAWARE yourapplication.exe 这里的yourapplication.exe 需要输入的是你的.net 应用程序的路径名加文件名。

    执行了这条语句后,我再次运行测试程序,内存可以申请到 2.5G了,比2GB模式下多了1G内存可以使用。

     

    最后多罗嗦一句,为什么.net 应用程序在 2GB 情况下只能申请最多 1.4-1.6 GB 的内存?

    这是因为.net 的垃圾回收器在工作时需要拷贝 live objects,.net framework 需要为它保留一定空间的内存来完成这些拷贝工作。这也是为什么Microsoft 建议asp.net 应用程序内存分配的上限最好设置为800M的原因.

    .net 应用程序如何优化性能,参见下面链接,大家有兴趣可以去看看,这里不再多说了,离主题有点远了。

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    4G内存的**——如何使用4GB(开启3GB和PAE)
    Windows Vista是一款相当耗费资源的操作系统,特别是内存。要提升系统性能,最简单也最有效的方式是为系统扩充尽可能多的内存,windows 7当然也不例外,虽然不像vista那么耗资源。现如今内存已是大白菜,4G及以上内存必定是趋势。windows 7最高能支持多少物理内存呢? 我们先来看看vista:


      根据微软给出的规格,除Starter版仅支持1GB内存外,其他版本的Windows Vista(32位)均能够支持4GB的“内存”——当然,指32位x86系统。需要注意的是,这里所谓的“4GB”并非等同于真正的物理内存,而是指可用的内存寻址空间。 


      对32位系统而言,4GB是其能够寻址空间的极限,除非通过PAE(Physical Address Extension 物理地址扩展)将4GB之上的内存通过映射的方式作为4GB空间中的页面来扩展。而在这4GB的地址空间中,必须为计算机的系统资源如BIOS、显卡、PCI-Express等PCI接口留出位置。 


       系统所支持的4GB寻址空间都包括哪些:首先,BIOS至少要占去512KB或者1MB,显卡要占去略大于其视频RAM的空间,比如说,对于在高分辩率下使用Aero Glass的情况而言,256MB显存是必需的,这就必须在4GB的寻址空间中为显卡的256MB视频RAM留出位置;第三,对基于x86的计算机系统而言,其还必须为其他的PCI设备保留相当部分的寻址空间,比如各种IO设备等。这样,系统在寻址真正的物理内存之前,系统中已经被各种资源占用512MB到1GB的寻址空间,也即是说,系统真正能够使用的物理内存大致在3 GB到3.4 GB之间。 


      这对于象Win7这样一款以1GB RAM越跳的系统而言,系统内存的可扩充空间实在太小,尤其与当年Windows XP 128MB-4GB的内存范围相比。而且,虽然Win7 X86从内核上来说应该是能够支持PAE的。当然,也需要硬件厂商特别是CPU、芯片组与主板厂商的配合。 


      另一方面,在32位的Windows系统——不仅仅Windows Vista / Win7中,所支持的4GB寻址空间被分成两部分:其中2GB可被应用程序使用,而另外的2GB则被系统内核占用。因此,即使对于系统中安装了4GB内存的Win7而言,应用程序所能够使用的内存也被限制在2GB之内,从而在某些情况下仍难免会出现“内存不足”的情况。对此,server用户虽然可以通过微软的4GT RAM Tuning来将内核的内存起始位置移至3GB处——以在Boot.ini中添加“/3GB”开关实现,即将为内核分配的虚拟地址空间缩小到1GB,而将应用程序可使用的地址空间扩展到3GB——但距理想程度仍有距离。 


      当然,如果64位,问题就好办多了,Windows Vista x64可支持的内存从8GB(Windows Vista Home Basic)到128GB(Windows Vista Ultimate),Win7也一样,类似的寻址限制不复存在。但在软件和游戏上,64位的用户要期望更多的软件和游戏厂家的支持。

    附:Vista / windows 7如何开启PAE
    1进入cmd:点击开始菜单,在搜索框中输入”cmd“,按下 Ctrl + Shift + Enter (进入cmd的管理员模式)
    2输入如下命令BCDEdit /set PAE forceenable Windows 这里的BCDEdit是关于命令行的启动配置编辑器。使用上面的命令,你能启用物理地址扩展(PAE),让支持的内存大于4GB


      Vista / windows 7开启3GB
    因为32位windows默认应用程序只能使用2G内存,剩下的都保留给系统内核了,所以还要开启3GB
    1进入cmd:点击开始菜单,在搜索框中输入”cmd“,按下 Ctrl + Shift + Enter (进入cmd的管理员模式)
    2,输入如下命令bcdedit /set increaseuserva 3072 来使得windows把2G以上的内存也分配给应用程序! 


    补充XP和 2003 的开启方法:


    1.打开 Windows 资源管理器。
      2.在“工具”菜单上,单击“文件夹选项”。
      3.在“查看”选项卡上,单击“显示所有文件和文件夹”,清除“隐藏受保护的操作系统文件”复选框,然后单击“确定”。如果显示警告对话框,单击“是”以继续。
      4.在根文件夹(如 C:)下查找 Boot.ini 文件并删除它的只读属性。
      5.打开 Boot.ini 文件,然后将 /PAE 参数添加到 ARC 路径中,如以下 Windows Server 2003 Datacenter Edition 示例所示:
      multi(0)disk(0)rdisk(0)partition(2)\%systemroot%="Windows Server 2003, Datacenter Edition" /PAE
      以xp为例,修改页面Boot.ini文件如下:
      timeout=30
      default=multi(0)disk(0)rdisk(0)partition(1)WINDOWS
      [operating systems]
      multi(0)disk(0)rdisk(0)partition(1)WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /PAE
      6.在“文件”菜单上,单击“保存”。
      7.还原 Boot.ini 文件的只读属性。
      8.为使更改生效,请重新启动计算机。

    由于在32位处理器架构下,对内存的访问限制在4GB以下的空间。为了突破 4GB的限制,现在的32位至强处理器采用一种叫PAE(物理地址扩展)的技术,来实现对超出4GB空间的物理地址的访问。PAE实际上采用了36位的地址总线,这样理论上可以支持64GB内存空间的寻址。

      PAE使得处理器可以支持访问更多的内存空间,但是这还需要操作系统的支持。由于操作系统本身也是32位的,所以需要在操作系统上做相应的处理来支持处理器。Windows系统采用AWE(Address Windowing Extension)来进行处理。具体结构如图2所示。此外,Linux系统在2.4内核以后也支持PAE和超过4GB的内存空间处理。

    32位系统,地址空间是4G。这个没错。用户空间指的是应用程序可以直接访问的地址,系统空间指的是应用程序不能直接访问,必须转到内核模式,由操作系统访问。任何操作系统都分用户空间和系统空间,Unix, Linux都是。
          Windows95, Windows 98, WindowsME系列2G用户空间 + 2G系统空间, 2G的系统空间中含有多个进程共享内存的空间和Win16的程序的代码,这就是Win9x系列容易死机的原因之一。
    WinNT, Win2000, WinXP系列2G用户空间 + 2G系统空间.(没有Win9x系列的进程共享内存等等)

    那么是不是我启动10个应用,那操作系统占有了10*2G这么多空间?


          首先,要搞清楚内存和地址空间的区别。内存是内存,地址空间是地址空间(太累了,我用memory代替内存,address space代替地址空间吧). 不管你有多少memory,256,还是512M,
    32位系统的每个应用都有4G的地址空间(只不过它不能访问上2G罢了).win2000下,你的程序最多可以使用2G空间,并不是说你还就可以分配2G的内存了,一般情况下,内存分配到
    一个值是会失败的。比如,你的物理memory = 256M,你的页交换文件大小=256M,那么你分配个516M内存看看,失败!物理内存和页交换文件加起来才512M呢.


          其次,操作系统真的占有了2G的内存吗?也不是。你的程序启动后,操作系统的代码和数据映射到程序的上面2G的空间,只是映射,不是说再启动一个实例放那儿。操作系统要映射一片内存的内容到一个区域是多简单的事情。操作系统一般把系统代码和数据映射到应用程序的上面2G的同一个地方。2个应用程序,它的上面2G空间的代码数据大致上一样(不完全一样,因为还是有些和应用程序相关信息,不过应用程序访问不到,得由系统通过内核态访问).严格说来,下面2G也不是应用程序都能用,0到64K这个空间就不能用,至于为什么,回到DOS时代吧!如果没搞多DOS那就不必要深究了。总之这是故意的。你的指针指到这儿肯定会出错,读都不能读。故意不让你读!

    哈哈。

          其实大多数应用程序比如你用VC写个程序,它的入口地址是从4M开始,也就是0x00400000,你看看 yourApp.hInstance的值吧!它就等于0x00400000.越讲越远了,

    为什么hInstance是程序的入口地址,跑题了!别扔砖头啊!

    那么应用程序怎么申请大于2GB的空间呢?

    办法1:就是上面的朋友提过的 通过 /3GB或者/USERVA开关。

    boot.ini 里头加上这个开关,系统会让出1G给应用程序访问。系统自己只用1G。这样子不是什么好办法。微软临时的方案而已。应用程序link时加上 LARGEADDRESSAWARE,在生成EXE的时候设置一个标志位,这个位系统看到了就让你访问 3G的空间(但是内存+页交换太小,你分配一样会失败).


    /3GB指定3G,/USERVA指定一个值,不是死的3G.

    办法2:通过AWE (Address Window Extension),地址窗扩展
    窗?是的,窗。你可以人认为是一个buffer,用来作为中间物,给2边的东西倒腾。

    socket接受发送数据也有窗的概念,一样的。


          要细看AWE,你到MSDN上查关键是AWE或者Address Window Extension。Google上Goole一把。你有了2G甚至更多的内存(啥机器都有,你不能怀疑一个32位系统装个20G内存会有问题吧?硬件可以做的)可以这么干。没有的话就别这么做了,没什么用.AWE的原理很简单,你在比如4G的物理内存上,分配的一片物理内存X, 你再分配的一片虚拟内存(地址空间)Y,把 X 和 Y 通过address window映射。你可以在这片虚拟内存里头访问4G的物理内存。最多访问多少要看你的参数设置了。


          AllocateUserPhysicalPages分配物理内存, VirtualAlloc申请虚拟内存,MapUserPhysicalPages进行映射。没什么难的.MSDN有个sample做这个事情,看看吧! 这么多关键字了应该好查到了。代码我不贴了 ,占篇幅。


          顺便说一下,内存文件映射并不把什么映射到(2~4G)这范围。它是进程共享数据的方式,并不是扩大内存的方式。不过如果你有个大硬盘,创建这么个映射来保存/修改数据也是可以的,这不要求大的内存。和内存没关系。

  • 相关阅读:
    【常用配置】Spring框架web.xml通用配置
    3.从AbstractQueuedSynchronizer(AQS)说起(2)——共享模式的锁获取与释放
    2.从AbstractQueuedSynchronizer(AQS)说起(1)——独占模式的锁获取与释放
    1.有关线程、并发的基本概念
    0.Java并发包系列开篇
    SpringMVC——DispatcherServlet的IoC容器(Web应用的IoC容器的子容器)创建过程
    关于String的问题
    Spring——Web应用中的IoC容器创建(WebApplicationContext根应用上下文的创建过程)
    <<、>>、>>>移位操作
    System.arraycopy(src, srcPos, dest, destPos, length) 与 Arrays.copyOf(original, newLength)区别
  • 原文地址:https://www.cnblogs.com/lidabo/p/8426006.html
Copyright © 2011-2022 走看看