Chrome 和 VSCode,每个进程能占用 1T 虚拟内存,有图有真相 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
richangfan
V2EX    Linux

Chrome 和 VSCode,每个进程能占用 1T 虚拟内存,有图有真相

  •  2  
  •   richangfan 2023-07-09 18:38:15 +08:00 4413 次点击
    这是一个创建于 829 天前的主题,其中的信息可能已经有所发展或是发生改变。

    截图

    15 条回复    2023-07-27 20:40:34 +08:00
    codehz
        1
    codehz  
       2023-07-09 18:46:05 +08:00
    virt 没啥好关注的。。
    wuzhewuyou
        2
    wuzhewuyou  
       2023-07-09 18:47:24 +08:00 via Android
    今天下英雄,唯使君与操耳
    hsfzxjy
        3
    hsfzxjy  
       2023-07-09 18:54:18 +08:00 via Android
    virt 不能说明什么啊
    GlobalNPC
        4
    GlobalNPC  
       2023-07-09 19:04:57 +08:00
    virt 只是系统映射给的大小,不代表实际使用的大小
    w568w
        5
    w568w  
       2023-07-09 21:58:25 +08:00 via Android
    写一行 brk() 把堆顶位置拉满,你的 hello world 也可以占 1TB virt
    systemcall
        6
    systemcall  
       2023-07-09 23:02:44 +08:00 via Android
    virt 这样很正常。我之前用过一个开发板,跑的 64 位系统,一共就几百 MB 内存,还没有 swap 和 zram ,底包自带的一堆东西就几百 G 几百 G 的划 virt ,只能说多亏了是 64 位系统,32 位系统估计早就 oom 了吧
    geekdonie
        7
    geekdonie  
       2023-07-09 23:43:19 +08:00
    这就是为啥它叫“虚拟”内存
    yanqiyu
        8
    yanqiyu  
       2023-07-09 23:46:59 +08:00   1
    虚拟内存就是纯粹的数字。有些分配器倾向于一启动就 mmap 出来一块超大内存再慢慢分配,所以看起来就是 1T/2T 的 VIRT
    但是不真正的读写这些内存,内核是不会真正分配页面的
    wxf666
        9
    wxf666  
       2023-07-09 23:57:48 +08:00
    @yanqiyu #8 系统要多少内存才能维护 1T 虚拟内存来着?好像是操作系统的页表那块内容吧?忘完了。。
    yanqiyu
        10
    yanqiyu  
       2023-07-10 16:22:23 +08:00 via Android
    @wxf666 没分配也不会写页表,只是记录下来某段地址成为“可用状态”(代价微乎其微),真正遇到缺页中断才会真正的分配页表
    wxf666
        11
    wxf666  
       2023-07-10 16:26:44 +08:00
    @yanqiyu #10 Emm... 换句话说,申请 1GB 虚拟内存,和 100TB 虚拟内存,操作系统付出的代价,是一样的吗?
    yanqiyu
        12
    yanqiyu  
       2023-07-10 18:40:10 +08:00
    @wxf666 是的,你可以试一下下面的代码,一口气分配 100T ,但是 RES/SHR 依然很小
    当然再大就超出了地址空间了
    ```
    #include <cerrno>
    #include <iostream>
    #include <sys/mman.h>

    int main(int, char **) {
    constexpr auto size = (size_t)100 << 40;
    auto address = mmap64(nullptr, size, PROT_READ | PROT_WRITE,
    MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
    if (address == MAP_FAILED) {
    std::cerr << "mmap failed \n errno:" << errno << std::endl;
    return 1;
    }
    std::cout << "mmap success, press enter to exit" << std::endl;
    std::getchar();
    munmap(address, size);
    return 0;
    }
    ```
    yanqiyu
        13
    yanqiyu  
       2023-07-10 18:47:51 +08:00
    @wxf666 这也是为什么有的语言的分配器倾向于直接要一个 T 再自己分配,好处就是不用频繁的用 syscall 找 os 要地址,一口气要个大的。
    LiangBryan
        14
    LiangBryan  
       2023-07-10 20:35:53 +08:00
    没什么好奇怪的,我的电脑也是这样。
    secondwtq
        15
    secondwtq  
       2023-07-27 20:40:34 +08:00   3
    一个典型的例子是 Haskell 的 GHC 编译器,这货(所编译出的程序)在版本 8 之后就是开局分配 1TB 的虚拟内存空间。这是对应的 tracker:gitlab.haskell.org/ghc/ghc/-/issues/9706 #9706: New block-structured heap organization for 64-bit Issues Glasgow Haskell Compiler / GHC GitLab
    根据这个 issue 的描述,在之前,GHC 的 allocator 会首先向 OS 申请叫做 megablock 的较大块内存,然后再分成叫做 block 的较小块内存,之后在 block 中处理具体的分配请求。而现在不需要 megablock 这个概念了(或者说只有一个全局的 1TB megablock ),大大简化了实现。

    这么做最明显的好处之一是,由于 GHC 使用 tracing GC ,在 GC 时需要检查一个指针是否指向堆中的数据( gitlab.haskell.org/ghc/ghc/-/wikis/commentary/rts/storage/heap-alloced heap alloced Wiki Glasgow Haskell Compiler / GHC GitLab ),因为可能有许多个 megablock ,这个检查在之前是非常麻烦的他们实现了一套 cache 机制,我觉得很像软件层的 TLB ,先用 tag 去找,找不到再去到表里面搜。而现在只有一个 megablock ,只需要一个全局变量记录它的地址,直接检查是不是在它的 1TB 范围内就可以了(这个应该还可以继续优化,因为理论上你可以向 OS 提出特定的对齐要求,这样直接一个 bitwise-and 搞定)。实现者声称在一些 benchmark 上获得了 8%+ 的提升。注意这个不是靠减少 syscall 得到的。
    当然,由于没有了 megablock 的概念,malloc 和 free 的过程也被简化了。

    当然,这个 trick 首先需要地址空间足够大,所以只能在 64 位环境下使用。
    另外在 Windows 上的实现有些不同,因为 Windows 的 memory overcommitment 似乎和 Linux 上不太一样。

    之所以要提 Windows 不只是因为原 issue 上重点关照了这方面,还是因为之前我关注到网络上的一些言论,说最好不要彻底关闭 Windows 的 pagefile ,会导致很多软件出问题,甚至包括 MSFT 官方的一些软件。我一直都很好奇,按理说有没有 pagefile/swap 并不是软件应该关心的问题,如果我 8GB DRAM+8GB pagefile 能正常工作,16GB DRAM 不带 pagefile 不应该更差。看到这个问题就觉得可能跟这个有关系。我的推测是 Windows 下的很多程序可能比较喜欢以当前系统的 DRAM 大小为系数来预分配内存,这样所有程序想要分配的内存总大小很容易超过 DRAM 大小,就必须要 pagefile 来兜个底。但是网上的建议是你哪怕开几 MB 的 pagefile 创建一下全国文明系统都不要彻底关掉,如果真的只有几 MB 的话就没啥作用了。不过 Windows 默认的 pagefile 设置是“系统自动管理”,不够的时候会自动扩容(虽然最多只能 3x DRAM 大小),并且 NTFS 还支持 Sparse file 。另一个因素是现在 Windows 主流软件几乎全员或多或少都要 GPU 加速,而 DRAM 和 VRAM 之间的数据传输也需要 memory map 。还有一个则是根据官方文档,Windows 的 CreateFileMappingW(INVALID_HANDLE_VALUE, ... (类似 MAP_ANON )是"backed by the system paging file",而在 Linux/BSD 上直接出来就是 anonymous page ,但是 Raymond Chen 澄清过( bytepointer.com/resources/old_new_thing/20130301_058_the_source_of_much_confusion_backed_by_the_system_paging_file.htm The source of much confusion: "backed by the system paging file" )这个有很多误会,"backed"是指"page out 的时候会扔到 pagefile 去",这样得到的内存空间其实和 HeapAllocate/VirtualAlloc() 是一样的,也就是说基本是一句废话。目前我没有时间或者没有方法来验证这些猜测,所以这个问题到现在还没搞明白,不知道 V 友有没有清楚具体原因的。

    Windows 下还有更加生草的问题和楼上所关心的“操作系统付出的代价”密切相关。由于 GHC 采用了这种新的内存管理模式,在老版 WSL 上会莫名奇妙地慢到不可用:github.com/microsoft/WSL/issues/1671 `stack ghc` painfully slow Issue #1671 microsoft/WSL GitHub 这个问题后来貌似被修复了,不过可见虚拟内存大小并非在所有情况下都无所谓。上面有人说开发板也可以跑,前提也是开发板的软件是比较成熟的。

    此外 Google 的 Go 实现在某些版本似乎也有类似的机制。至于 Chrome 这个事情,https://unix.stackexchange.com/a/741548 Why Google Chrome is reserving Terabytes scale virtual memory? 这个回答指出这和 V8 引擎在近年实现的一个新的安全功能有关。V8 中的一些 bug 可能允许攻击者利用 V8 内部代码实现内存读写,因此这个新的机制会预先分配 1TB 的虚拟地址空间,并将 JS 程序的数据全都分配在这里面,地址则使用 40-bit 数存储。这样就把类似攻击的影响面限制在了这 1TB 范围之内。

    最后必须批评类似话题常见的一种风气对你没有影响就不用管,这属于问了 Y ,然后回答者自作主张去回答 X 。典型是这个帖子:reddit.com/r/linuxquestions/comments/w4im5m/chrome_using_11_terabytes_of_virtual_memory 这里很明显这个 sub 的平均技术水平一般不清楚虚拟地址空间概念的比比皆是,不过鉴于本身就是 /r/linuxquestions 倒也没啥奇怪的。但是就算虚拟地址空间占用对用户没有什么意义,为什么别的进程都很正常,就你 Chrome 搞特殊呢?这本身就是个很有趣的问题。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1194 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 17:32 PVG 01:32 LAX 10:32 JFK 13:32
    Do have fith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86