这个问题我想应该是仁者见仁智者见智的,所以没有必要diss别人的回答,大部分人都可以在自己的经验范围内给出一个合理的参考做法,这是没有问题的,而且应该没有人会说自己是标准答案,因为这本身就没有标准答案。所以我下面不会说“应该设置为XXX”这种话,如果你单纯对此有所期待,那么可以不用费时间向下阅读。
既然这个问题推到我这了,我也凑个热闹稍微说一个个人看法。首先我不是Windows用户,但是虚拟内存不是只有Windows用户才会面临的概念。因为虚拟内存本身是一个操作系统层面的通用概念。在说如何设置虚拟内存之前,我先简单说一下什么是虚拟内存。
先来看一个例子,有这样一个程序:
// mytest.c#include<stdio.h>#include<stdlib.h>#include<errno.h>intmain(intargc,char*argv[]){size_tn=0;n=atoi(argv[1]);if(!malloc(n*1024*1024*1024)){perror("malloc");return1;}while(1);return0;}
我们用这个程序来申请内存分配,先来看一下我当前机器的内存情况:
$ free -htotal used free shared buff/cache availableMem: 15Gi 2.2Gi 9.6Gi 350Mi 3.3Gi 12GiSwap: 7.6Gi 0B 7.6Gi
可以看到物理内存有15G左右,当前有12G available,交换空间或者说这个题目所指的“虚拟内存”有7.6G。那么大家觉得我申请分配多少,或导致no memory的错误呢?
首先一次性申请不超过物理内存应该是没有问题的,那一次性申请超过物理内存,但是小于物理内存加“虚拟内存”的总大小呢?
$ ./mytest 18
没有问题,返回成功。那我们一次性申请超过物理内存加“虚拟内存”的总和呢?
$ ./mytest 50malloc: Cannot allocate memory
这就不行了,系统直接返回错误,告诉你不能分配那么多内存。那我们每次申请5GiB,连续申请十次呢?
$ for i in `seq 1 10`;do ./mytest 5 & done
都没有问题,全部成功。为什么一次性申请50G不行,分批就可以呢?因为一次性申请50G,系统直接就能判定没有这么多。但是如果你分开使用,虽然我们每次都申请5G,但系统并没有真的给我们5G,只有在真的需要写入的时候,才会真的让这5G对应物理地址。我们现在可以看到,即使我们做了5G * 10的malloc操作,内存的状态仍然是没有变化:
$ free -htotal used free shared buff/cache availableMem: 15Gi 2.2Gi 9.6Gi 350Mi 3.3Gi 12GiSwap: 7.6Gi 0B 7.6Gi
说明这5G * 10的内存根本没有实际分配。为了让内存得到实际分配,我们对malloc出来的内存进行写入操作,将程序改为:
...p=malloc(n*1024*1024*1024);if(!p){perror("malloc");return1;}memset(p,0xff,n*1024*1024*1024);...
这回我们先试试分配并写5GB:
$ ./mytest 5$ free -h$ free -htotal used free shared buff/cache availableMem: 15Gi 7.2Gi 4.6Gi 357Mi 3.3Gi 7.2GiSwap: 7.6Gi 0B 7.6Gi
可以看到物理内存的used从2.2变成7.2G。如果我们要分配并写超过物理内存大小,但是小于物理内存加上“虚拟内存”大小呢?
$ ./mytest 17$ free -htotal used free shared buff/cache availableMem: 15Gi 14Gi 234Mi 83Mi 255Mi 155MiSwap: 7.6Gi 4.8Gi 2.8Gi
我们可以看到这么做也是可以的,而且物理内存已经基本全部占用,“虚拟内存”也占用了很大一部分。这时候我写这个回答也变得有一点点卡顿了,因为我的内存已经所剩无多了。但还可以接受,而且渐渐缓解,因为我当前写回答的进程是主要活跃进程,mytest那个测试进程占用的内存应该被部分换出到硬盘上的虚拟内存去了,给我当前的浏览器进程预留了足够的物理内存。
在虚拟内存已经所剩无多的状态下,我们尝试超额申请内存试试,我们一共加起来也就剩3G左右了,我们申请并写入5G试试。注意此时是有风险的,不同的系统可能会有不同的应对方式。在实际这么做之前,我预计我的系统(kernel-5.3.11-100.fc29.x86_64)应该会触发OOM killer,杀死系统认为大量浪费占用内存的进程,以维持系统正常运行(当然不排除误杀我当前的浏览器进程……但我认为概率不大,毕竟上面有一个占了17G的无用进程顶在我前面呢:)。让我们试试看(我先保存个草稿;):
$ ./mytest 5
在经过了一小段时间的卡顿后,这个程序执行成功了,我的浏览器没有被杀死,系统也没有崩溃。而且在预料之内的,那个占用17G内存的程序被内核主动杀死了:
./mytest 17Killed$ dmesg...[17122.987802] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user.slice/user-1000.slice/session-2.scope,task=mytest,pid=25832,uid=1000[17122.987809] Out of memory: Killed process 25832 (mytest) total-vm:17828096kB, anon-rss:11570352kB, file-rss:0kB, shmem-rss:0kB[17123.578327] oom_reaper: reaped process 25832 (mytest), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
通过上述例子,我们可以对物理内存和“虚拟内存”有一个大概的印象。下面我们就来简单说一下什么是虚拟内存。