增加虚拟内存而不增加VmSize

我在Google和这个网站上search了我的问题,但是我仍然不明白这个解决scheme。

我有一块RECV数据的MPI程序。 程序在虚拟内存不足的情况下在大arrays上崩溃,所以我开始考虑/proc/self/status文件。

MPI_RECV之前是:

 Name: model.exe VmPeak: 841640 kB VmSize: 841640 kB VmHWM: 15100 kB VmRSS: 15100 kB VmData: 760692 kB 

之后:

 Name: model.exe VmPeak: 841640 kB VmSize: 841640 kB VmHWM: 719980 kB VmRSS: 719980 kB VmData: 760692 kB 

我在Ubuntu上testing它,通过系统监视器,我看到这个内存在增加。 但我很困惑, VmSize (和VmPeak )参数没有改变。

问题是 – 真实内存使用情况的指标是什么?

这是否意味着真正的指标是VmRSS ? (和VmSize只分配但仍然没有使用内存)

Solutions Collecting From Web of "增加虚拟内存而不增加VmSize"

(对您的问题的可能的解决方案是最后一段)

大多数具有虚拟内存的现代操作系统的内存分配是一个两阶段的过程。 首先,进程的虚拟地址空间的一部分被保留,进程的虚拟内存大小( VmSize )相应地增加。 这在所谓的进程页表中创建条目。 页面最初不与物理内存帧关联,即没有实际使用物理内存。 每当这个分配部分的一部分被实际读取或写入时,就会发生页面错误,操作系统从物理内存安装(映射)空闲页面。 这增加了进程的驻留集大小( VmRSS )。 当某个其他进程需要内存时,操作系统可能会将一些不常使用的页面的内容(“不常使用的页面”的定义依赖于高度实现)存储到某些永久存储器(大多数情况下是硬盘驱动器,或者通常交换设备),然后取消映射。 这个过程减少了RSS,但保持VmSize不变。 如果稍后访问此页面,则会再次发生页面错误,并将返回该页面。 虚拟内存分配只有在释放虚拟内存时才会减少。 请注意, VmSize也会计算内存映射文件(即可执行文件及其链接的所有共享库或其他明确映射的文件)和共享内存块。

在进程中有两种通用类型的内存 – 静态分配的内存和堆内存。 静态分配的内存保留所有常量和全局/静态变量。 它是数据段的一部分,其大小由VmData度量标准显示。 数据段也承载了程序堆的一部分,在这里正在分配动态内存。 数据段是连续的,即它从一个特定的位置开始向上向上堆栈(从一个非常高的地址开始然后向下增长)。 数据段中的堆的问题在于它由一个特殊的堆分配器来管理,该堆分配器负责将连续的数据段细分为更小的内存块。 另一方面,在Linux中动态内存也可以通过直接映射虚拟内存来分配。 这通常是为了节省内存而进行的大分配,因为它只允许分配多倍页面大小的内存(通常是4 KiB)。

堆栈也是重度内存使用的重要来源,特别是在自动(堆栈)存储中分配大数组时。 堆栈从可用虚拟地址空间的最顶端开始向下增长。 在某些情况下,它可能会到达数据段的顶部,或者可能到达其他虚拟分配的末尾。 那么坏事发生了。 堆栈大小在VmStack指标中,也在VmSize 。 人们可以总结如下:

  • VmSize占所有虚拟内存分配(文件映射,共享内存,堆内存,任何内存),几乎每次新内存分配时都会增长。 几乎是因为如果新的堆内存分配是在数据段中释放旧分配的地方进行的,则不会分配新的虚拟内存。 只要虚拟分配被释放,它就会减少。 VmPeak跟踪VmPeak的最大值 – 它只能在时间上增加。
  • VmRSS随着内存的访问而增长,随着内存被分页到交换设备而降低。
  • VmData随着堆的数据段部分被使用而增长。 它几乎不会缩小,因为当前的堆分配器保留释放的内存,以防将来的分配需要它。

如果您正在使用InfiniBand或其他基于RDMA的VmLck运行集群,另一种类型的内存将进入运行状态 – 锁定的(已注册的)内存( VmLck )。 这是不允许被分页的内存。 MPI如何增长和缩小取决于MPI的实施。 有些人从来没有取消注册一个已经注册的块(关于为什么这里太复杂的技术细节不能在这里描述),其他人这样做是为了更好的使用虚拟内存管理器。

在你的情况下,你说你正在运行一个虚拟内存大小的限制。 这可能意味着此限制设置得太低,或者您遇到了OS限制。 首先,Linux(和大多数Unix)有通过ulimit机制施加人为限制的手段。 在shell中运行ulimit -v会告诉你在KiB中虚拟内存大小的限制。 您可以使用ulimit -v <value in KiB>设置限制。 这只适用于当前shell和其子孙,孙辈等产生的进程。 如果要在远程节点上启动,则需要指示mpiexec (或mpirun )将此值传播到所有其他进程。 如果您正在像LSF,Sun / Oracle Grid Engine,Torque / PBS等工作负载管理器的控制下运行您的程序,则存在控制虚拟内存大小限制的作业参数。 最后但并非最不重要的是,32位进程通常限制在2 GiB的可用虚拟内存。