当前位置首页 > 初中物理 > 辅导探讨

申请8G内存是没问题的,为什么他就无法申请成功?

更新时间:2023-08-20 文章作者:佚名 信息来源:网络整理 阅读次数:

大家好,我是小林。zUJ物理好资源网(原物理ok网)

虽然这篇文章之前已经发表过,但最近有读者向我反映,我文章中的实验是在64位操作系统和2G化学显存中进行的。 申请8G显存是没有问题的,他也是在这个环境下。 为什么他很难申请成功?zUJ物理好资源网(原物理ok网)

后来我去查了一下他的情况。 原来是和Linux的参数有关。 该参数主要定义是否允许进程请求的内存存储是激进的。zUJ物理好资源网(原物理ok网)

之后这位读者很细心,写了一篇世界文献,总结了我和他交流的过程。zUJ物理好资源网(原物理ok网)

现在我补充了这部分内容,比之前的文章更加全面。zUJ物理好资源网(原物理ok网)

废话不多说,开局就火热!zUJ物理好资源网(原物理ok网)

文本zUJ物理好资源网(原物理ok网)

我看到有读者在群里讨论这种笔试题:zUJ物理好资源网(原物理ok网)

其中,第一个问题“在4GB化学显存的机器上申请8G显存会怎么样?” 有一个很大的争议。 有人说申请会失败,有人说申请可以成功。zUJ物理好资源网(原物理ok网)

不带后置条件回答这个问题就是耍流氓。 这个问题需要考虑三个后置条件:zUJ物理好资源网(原物理ok网)

那么,我们来谈谈场景。zUJ物理好资源网(原物理ok网)

操作系统虚拟内存大小zUJ物理好资源网(原物理ok网)

当应用程序通过函数申请显存时,实际上是在申请虚拟显存,此时不会分配化学显存。zUJ物理好资源网(原物理ok网)

当应用程序读写虚拟显存时,CPU就会访问虚拟显存。 这时会发现虚拟显存没有映射到化学显存,CPU会引发缺页中断,进程会从用户态切换到内核态。 ,并将缺页中断交给内核的(缺页中断函数)处理。zUJ物理好资源网(原物理ok网)

页面错误中断处理程序将检查是否有空闲的数学视频内存:zUJ物理好资源网(原物理ok网)

32位操作系统和64位操作系统的虚拟地址空间的大小是不同的。 在Linux操作系统中,虚拟地址空间内部分为两部分:内核空间和用户空间,如下图:zUJ物理好资源网(原物理ok网)

从这里可以看出:zUJ物理好资源网(原物理ok网)

32位操作系统场景zUJ物理好资源网(原物理ok网)

现在我们可以回答这个问题了:在32位操作系统、4GB化学显存的机器上申请8GB显存怎么样?zUJ物理好资源网(原物理ok网)

由于32位操作系统,进程最多只能申请3GB的虚拟显存空间,所以如果进程申请8GB的显存,就会在申请虚拟显存阶段失败(我没有32位操作系统测试,恐怕失败的错误是,即申请显存困难而失败)。zUJ物理好资源网(原物理ok网)

64位操作系统场景zUJ物理好资源网(原物理ok网)

如果在64位操作系统、4GB化学显存的机器上申请8G显存会怎么样?zUJ物理好资源网(原物理ok网)

64位操作系统,进程可以使用128TB的虚拟显存空间,所以进程申请8GB显存是没有问题的,因为进程申请显存就是申请虚拟显存,只要由于虚拟显存不被读写,操作系统不会分配化学显存。zUJ物理好资源网(原物理ok网)

我们可以做一个简单的测试,我的服务器是64位操作系统,数学内存只有2GB:zUJ物理好资源网(原物理ok网)

zUJ物理好资源网(原物理ok网)

现在,在机器上,我已经连续四次申请了1GB显存,也就是说,我一共申请了4GB显存。 请注意,以下代码只是分配虚拟视频内存,并没有使用它:zUJ物理好资源网(原物理ok网)

#include 
#include 
#include 
#include 

#define MEM_SIZE 1024 * 1024 * 1024

int main() {
    char* addr[4];
    int i = 0;
    for(i = 0; i < 4; ++i) {
        addr[i] = (char*) malloc(MEM_SIZE);
        if(!addr[i]) {
            printf("执行 malloc 失败, 错误:%sn",strerror(errno));
          return -1;
        }
        printf("主线程调用malloc后,申请1gb大小得内存,此内存起始地址:0X%pn", addr[i]);
    }
    
    //输入任意字符后,才结束
    getchar();
    return 0;
}
zUJ物理好资源网(原物理ok网)

运行这段代码后,你可以听到我的数学显存似乎只有2GB,但程序正常分配4GB虚拟显存:zUJ物理好资源网(原物理ok网)

我们可以通过以下命令查看进程(测试)的虚拟显存大小:zUJ物理好资源网(原物理ok网)

# ps aux | grep test
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      7797  0.0  0.0 4198540  352 pts/1    S+   16:58   0:00 ./test
zUJ物理好资源网(原物理ok网)

其中,VSZ表示进程使用的虚拟内存大小,RSS表示进程使用的数学内存大小。 可以看到VSZ大小为4GB虚拟显存。zUJ物理好资源网(原物理ok网)

开头提到的读者给我反馈,说他自己做了这个实验,后来发现在64位操作系统、2G化学内存的机器上,申请4GB虚拟内存时失败了。 为什么?zUJ物理好资源网(原物理ok网)

失败错误:zUJ物理好资源网(原物理ok网)

我当时查了一下,发现和Linux中的参数有关。 可以使用cat /proc/sys/vm/查看该参数。 该参数接受三个值:zUJ物理好资源网(原物理ok网)

当时的参数是默认值0,所以申请失败的原因可能是内核认为我们申请的显存太大了,它认为不合理,所以()返回了一个错误。 这里申请4GB虚拟显存失败的朋友可以将其设置为1,就可以了。zUJ物理好资源网(原物理ok网)

echo 1 > /proc/sys/vm/overcommit_memory 
zUJ物理好资源网(原物理ok网)

设置为1后,读者机器可以正常申请4GB虚拟显存。zUJ物理好资源网(原物理ok网)

然而我的环境是0,在64系统和2G化学内存场景下,我也可以成功申请4G显存。 我怀疑不同版本的内核可能有不同的算法来检查显存为0时申请是否合理。zUJ物理好资源网(原物理ok网)

其实如果你申请大显存的时候不想被内核的算法干扰去检查内存申请是否合理,设置为1就可以了。zUJ物理好资源网(原物理ok网)

那么设置这个为1后,64位主机是否可以申请近128T的虚拟显存呢?zUJ物理好资源网(原物理ok网)

不一定,这取决于您服务器的数学内存的大小。zUJ物理好资源网(原物理ok网)

读者服务器化学显存为2GB。 经过实验发现,在申请128T虚拟显存之前,进程就被杀掉了。zUJ物理好资源网(原物理ok网)

注意这次不是,说明不是内存申请的问题,而是触发了OOM。zUJ物理好资源网(原物理ok网)

但是为什么会触发OOM呢?zUJ物理好资源网(原物理ok网)

这取决于你的主机的“物理显存”是否足够大。 虽然申请的是虚拟显存,但只要不被访问,就不会映射到化学显存,并且在申请虚拟显存的过程中,仍然使用化学显存(如内核保存虚拟显存的数据结构,也占用化学显存),如果你的主机只有2GB数学显存,那么很有可能会触发OOM。zUJ物理好资源网(原物理ok网)

可以使用top命令,点击m两次,通过进度条观察化学内存使用情况。zUJ物理好资源网(原物理ok网)

可以看到,在申请虚拟显存的过程中,数学显存的使用量还在不断减少。zUJ物理好资源网(原物理ok网)

直接显存回收后,仍然没有空间可供该进程回收。 这时候就会触发OOM,所有可以杀死的进程都会被计分。 分数越高,越容易被杀死。zUJ物理好资源网(原物理ok网)

事实上,这个进程在这里得分最高,所以操作系统会杀死这个进程,所以它会出现在最后,而不是。zUJ物理好资源网(原物理ok网)

这样拥有2GB数学显存的64位操作系统就不能申请128T虚拟显存了?zUJ物理好资源网(原物理ok网)

虽然可以,但是里面的情况是swap还没有开启。zUJ物理好资源网(原物理ok网)

使用的形式是开辟1GB的交换空间,然后进行实验:zUJ物理好资源网(原物理ok网)

发现已经出现电脑的物理内存怎么查看,并且似乎已经在这里取得了成功,zUJ物理好资源网(原物理ok网)

打开估算器估算一下,发现已经申请了127.998T虚拟显存。zUJ物理好资源网(原物理ok网)

其实我们不可能申请整个128T的用户空间,因为程序本身也需要申请虚拟空间zUJ物理好资源网(原物理ok网)

尝试申请127T虚拟显存:zUJ物理好资源网(原物理ok网)

发现进程没有被杀死,也没有,而且恰好是127T虚拟显存空间。zUJ物理好资源网(原物理ok网)

在顶部我们可以看到已经申请了127T虚拟显存的进程。zUJ物理好资源网(原物理ok网)

Swap机制的作用zUJ物理好资源网(原物理ok网)

在32位/64位操作系统环境下申请的虚拟显存超过数学显存后会出现什么情况?zUJ物理好资源网(原物理ok网)

如果程序请求的虚拟显存没有被使用,则不会占用数学空间。 操作系统访问这块虚拟显存后,就可以分配化学显存了。zUJ物理好资源网(原物理ok网)

如果请求的数学内存大小超过了空闲化学内存大小,则取决于操作系统是否启用了Swap机制:zUJ物理好资源网(原物理ok网)

互换机制是什么?zUJ物理好资源网(原物理ok网)

当系统的数学显存不够时,需要释放数学显存中的部分空间,以供当前运行的程序使用。 这些释放的空间可能来自于一些长时间没有运行的程序。 释放的空间将暂时保存到C盘。 当这些程序即将运行时,保存的数据将从C盘恢复到显存。 。zUJ物理好资源网(原物理ok网)

另外,当显存使用出现压力时,就会开始触发显存回收行为,会先将那些不经常访问的显存移至C盘,然后释放那些显存以供使用通过其他更需要它的进程。 当再次访问那些显存时,只需再次从c盘读取显存即可。zUJ物理好资源网(原物理ok网)

这些,将显存数据交换出C盘以及将数据从C盘恢复到显存的过程就是Swap机制负责的。zUJ物理好资源网(原物理ok网)

交换就是使用一块c盘空间或者本地文件作为显存,其中包括换出和换入两个过程:zUJ物理好资源网(原物理ok网)

Swap换入换出的流程如右图所示:zUJ物理好资源网(原物理ok网)

使用Swap机制的好处是应用程序实际可以使用的显存空间将远远超过系统的数学显存。 由于硬盘空间的价格远低于显存的价格,这些方法无疑是经济且廉价的。 事实上,频繁的硬盘读写会显着提高操作系统的运行速度,这也是Swap带来的恶果。zUJ物理好资源网(原物理ok网)

Linux中的Swap机制在显存不足或者显存空闲时会被触发:zUJ物理好资源网(原物理ok网)

Linux提供了两种不同的方式来启用Swap,分别是交换分区(Swap)和交换文件(Swap file):zUJ物理好资源网(原物理ok网)

Swap 可以换入和换出哪些类型的显存?zUJ物理好资源网(原物理ok网)

由于内核缓存的文件数据在c盘都有对应的文件,因此当回收文件数据时,可以直接写回对应的文件。zUJ物理好资源网(原物理ok网)

不过,和进程的堆、栈数据一样,它们没有实际的载体,这部分显存被称为匿名页。 而这部分显存很可能会被再次访问,所以显存不能直接释放,所以需要有一个可以保存匿名页面的硬盘载体,而这个载体就是Swap分区。zUJ物理好资源网(原物理ok网)

匿名页面回收的形式是通过Linux的Swap机制。 Swap会先将不经常访问的显存转移到C盘,然后释放这些显存供其他更需要的进程使用。 当再次访问那些显存时,只需再次从c盘读取显存即可。zUJ物理好资源网(原物理ok网)

那么我们通过两个实验,看看如果申请的化学显存超过了化学显存会出现什么情况呢?zUJ物理好资源网(原物理ok网)

实验一:不启用Swap机制zUJ物理好资源网(原物理ok网)

我的服务器是64位操作系统,数学内存只有2GB,并且没有Swap分区:zUJ物理好资源网(原物理ok网)

zUJ物理好资源网(原物理ok网)

我们把上面的代码改一下,这样申请了4GB的虚拟显存后,通过一个函数来访问这个虚拟显存,看看没有Swap分区会发生什么?zUJ物理好资源网(原物理ok网)

#include 
#include 
#include 
#include 

#define MEM_SIZE 1024 * 1024 * 1024

int main() {
    char* addr[4];
    int i = 0;
    for(i = 0; i < 4; ++i) {
        addr[i] = (char*) malloc(MEM_SIZE);
        if(!addr[i]) {
            printf("执行 malloc 失败, 错误:%sn",strerror(errno));
            return -1;
        }
        printf("主线程调用malloc后,申请1gb大小得内存,此内存起始地址:0X%pn", addr[i]);
    }

    for(i = 0; i < 4; ++i) {
        printf("开始访问第 %d 块虚拟内存(每一块虚拟内存为 1 GB)n", i + 1);
        memset(addr[i], 0, MEM_SIZE);
    }
    
    //输入任意字符后,才结束
    getchar();
    return 0;
}
zUJ物理好资源网(原物理ok网)

运行结果:zUJ物理好资源网(原物理ok网)

可以看到,在访问第二个虚拟显存(每个虚拟显存为1GB)时,进程(test)因为超出了机器的化学显存(2GB)而被操作系统杀死。zUJ物理好资源网(原物理ok网)

通过查看系统日志可以发现进程被操作系统的OOM机制杀死,日志中报了Outof错误,即发生了OOM(内存溢出错误)。zUJ物理好资源网(原物理ok网)

什么是 OOM?zUJ物理好资源网(原物理ok网)

显存溢出(OutOf,简称OOM)是指应用系统中存在难以回收的显存或者使用了过多的显存,最终导致程序运行使用的显存少于可以提供的最大视频内存。 此时程序无法运行,系统会提示显存溢出。zUJ物理好资源网(原物理ok网)

实验2:启用Swap机制zUJ物理好资源网(原物理ok网)

我用我的电脑进行测试,我的电脑是64位操作系统,化学内存为8GB,当前Swap分区大小为1GB(注意这个大小不是固定的,Swap分区总大小会改变)动态地,当不使用Swap分区时,Swap分区的总大小为0;当使用Swap分区时,Swap分区的总大小将减少为1GB;当Swap分区的使用大小超过1GB时,Swap分区的总大小会减少到2GB;当Swap分区的大小超过2GB时,Swap分区的总大小会减少到3GB,以此类推,这个大概是macos自己实现的,而Linux分区是固定大小的,Swap分区不会根据使用情况手动减少)。zUJ物理好资源网(原物理ok网)

为了方便观察c盘的I/O情况,我们对上面的代码进行改进。 分配32GB虚拟显存(计算机化学显存为8GB)后,通过while循环频繁访问虚拟显存。 代码如下:zUJ物理好资源网(原物理ok网)

#include 
#include 
#include 

#define MEM_SIZE 32 * 1024 * 1024 * 1024

int main() {
    char* addr = (char*) malloc((long)MEM_SIZE);
    printf("主线程调用malloc后,目前共申请了 32gb 的虚拟内存n");
    
    //循环频繁访问虚拟内存
    while(1) {
          printf("开始访问 32gb 大小的虚拟内存...n");
          memset(addr, 0, (long)MEM_SIZE);
    }
    return 0;
}
zUJ物理好资源网(原物理ok网)

运行结果如下:zUJ物理好资源网(原物理ok网)

可以看到,在Swap分区的情况下,虽然电脑显存为8GB,但是申请并使用32GB显存是没有问题的。 程序运行正常,没有出现OOM的情况。zUJ物理好资源网(原物理ok网)

从右图可以看出,该进程的显存显示为32GB(这个不要理解为占用的化学显存,而是已经访问过的虚拟显存的大小,即大小已在数学显存中的显存),系统使用的Swap分区达到2.3GB。zUJ物理好资源网(原物理ok网)

这时,我的电脑笔记本的C盘开始发出“沙沙”的声音。 通过检查c盘的I/O状态,可以看到c盘的I/O已经达到了峰值,特别高:zUJ物理好资源网(原物理ok网)

有了Swap分区,是不是就意味着进程可以使用的显存是无限的呢?zUJ物理好资源网(原物理ok网)

其实并不是。zUJ物理好资源网(原物理ok网)

我把里面的代码改成申请64GB显存后电脑的物理内存怎么查看,当进程申请完64GB虚拟显存后,就会使用56GB(这个不要理解为占用的化学显存,而是虚拟显存的大小)已经访问过的内存,也就是数学上显存中已经使用过的显存大小),该进程就会被系统杀死,如右图所示:zUJ物理好资源网(原物理ok网)

当系统多次尝试回收显存,但仍然难以满足所需的显存大小时,进程就会被系统杀死,这意味着OOM已经发生。zUJ物理好资源网(原物理ok网)

总结zUJ物理好资源网(原物理ok网)

至此,验证完成。 简要总结:zUJ物理好资源网(原物理ok网)

超过!zUJ物理好资源网(原物理ok网)

悠悠球!zUJ物理好资源网(原物理ok网)

发表评论

统计代码放这里