内存分配-如何将15GB等同于2GB?

4

我的一个主要应用程序在运行时崩溃了。

我想找出是否与系统的内存分配问题有关。因此,我创建了一个小型测试程序来分配1GB的内存,并同时运行了15个这样的进程,总共使用了15GB的RAM。

然而,当我运行这个程序时,任务管理器显示它只占用了2GB的RAM?这怎么可能呢?

我编写了如下示例代码:

char *ptr[1024];
for ( i = 0 ; i < 1024 ; ++i )
{
    ptr[i] = new char[1024 * 1024];
    std::cout << " Allocated 1024 MB" << i << " th time " << std::endl;
}

5
操作系统可能存在过度提交的情况,也就是说,“new”返回一个有效的指针,尽管内存不足。如果尝试向获取的内存写入实际数据,则进程可能会被终止。 - user529758
2
任务管理器不显示“已占用内存量”。它显示的是工作集,这是一件不同的事情。 - Roman R.
5个回答

13

Windows 是一种按需页面虚拟内存操作系统。使用 operator new 分配内存只会分配 虚拟 内存,只有当你实际 访问 内存时才会开始使用 物理 内存,即 RAM。根据你所提供的信息,你尚未进行访问。

你可以通过触碰每个 4096 字节来强制分配 RAM,最好写入内容,否则它将被优化掉:

    size_t size = 1024 * 1024;
    ptr[i] = new char[size];
    for (size_t j = 0; j < size; j += 4096) ptr[i][j] = 0;

但这样做毫无意义,只会减慢程序运行速度。实际上并没有测试任何东西,在Windows上进程不可能用完内存。将任务管理器切换到程序员模式,添加提交大小一栏,那是真正的数字。


请注意,它确保在必要时提供空间。与某些操作系统不同,它不会撒谎,然后不得不开始杀人以满足内存需求。 - Billy ONeal
@Hans Passant:我很想有您提供技术背景的链接。 - user2249683
@DieterLücking:如果不是很多应用程序像分配1MB来读取文件一样,如果文件要小得多,则不会将其调整回来(大型静态分配也是如此)。操作系统之所以这样做,是因为总体而言,它比进行大量“填充所有页面”更有效率和更分散。只有当所有内存被许多不同的应用程序高度使用时,才会真正引起问题-这可能意味着您的机器内存不足。 - Mats Petersson

8
尝试将数据存储在大数组中。可以使用Memset来完成。 如果您不触及它,则可能只存在于虚拟内存中,所以您看到的实际上是内存。

谢谢 Dale。通过使用 memset 解决了这个难题。 - nsivakr
那是一件毫无意义的事情,它只会减慢程序的运行速度。 - Hans Passant
@HansPassant:完全不是这样,它会故障所有这些页面并创建物理页面。否则,此分配的内存仅指向虚拟零页。由于OP想要强制系统分配内存,所以这是正确的做法。 - Damon
@Damon - “强制系统分配内存”的目的是什么?这个测试有什么作用?你认为这个测试会失败吗? - Hans Passant
@HansPassant 的意思是进行实验,更好地理解操作系统如何管理内存。 - Neil Kirk
@HansPassant:OP的前提是“系统内存分配问题”。我不知道那是什么(也不认为在主流操作系统上可能存在)。无论如何,OP显然想要一种VM压力测试。为此,您必须触摸页面。 - Damon

1
也许操作系统会过度承诺,即使内存不足,operator new返回一个有效(非NULL)指针。尝试向获得的内存实际写入内容,你的进程可能会被终止(或至少物理内存使用量会增加)。

1
操作系统(无论是Windows、Linux还是MacOS)并不期望所有分配内存的进程都真正使用所有内存。很多程序会做一些事情,如分配1MB来存储一个文件,然后填充14KB的文件数据(因为这比计算文件实际大小并分配正确数量的内存更容易)。因此,它不会费力地为可能不会使用的内存实际提供物理内存页面,而是将其保留在虚拟空间中,然后在实际使用内存时寻找一些物理内存。
因此,在任务管理器中显示的内存量只是您正在使用的实际内存,而不是您已经分配但从未使用过的内存。
如果您编写一个循环,写入您分配的每256或1024个字节,它应该会“增长”,并显示您实际分配的内存量。

0

http://en.wikipedia.org/wiki/Virtual_memory

你实际上是在填充你的页面文件(pagefile)中的数据。操作系统看到你正在分配大量的数据,但在你使用它之前,这些数据不会从页面文件中被拉入主内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接