V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
yazinnnn
V2EX  ›  程序员

JVM 战士请教一个问题,各种语言都是怎样控制内存上限的?

  •  
  •   yazinnnn · 2022-06-02 09:58:50 +08:00 · 5477 次点击
    这是一个创建于 934 天前的主题,其中的信息可能已经有所发展或是发生改变。

    类似于 java heap(-Xmx1024m)的设置,各种语言都是怎样设置的?

    比较想知道 .net go swift rust node php haskell 等等

    53 条回复    2022-06-23 22:39:48 +08:00
    timpaik
        1
    timpaik  
       2022-06-02 10:12:48 +08:00 via Android
    Rust: 你创建多少变量 /结构体就占用多少内存,变量出了作用域立马释放就不占内存了,没有虚拟机,也不存在 GC ,更没有内存上限的问题
    pengtdyd
        2
    pengtdyd  
       2022-06-02 10:21:13 +08:00   ❤️ 3
    C : 内存上限?老子说什么是上限什么就是上限!
    andyhuzhill
        3
    andyhuzhill  
       2022-06-02 10:30:49 +08:00
    C C++的内存上限只和操作系统和硬件有关吧
    westoy
        4
    westoy  
       2022-06-02 10:36:45 +08:00   ❤️ 2
    cgroups 大法好
    kkocdko
        5
    kkocdko  
       2022-06-02 10:37:16 +08:00 via Android   ❤️ 4
    楼上几位能不能看清题再答。题主是“主观需要上限功能”而不是“被上限所困扰”。

    远古时代可以用 ulimit ,现在主要是在内存分配器上动手脚,比如可以 hook 一下 malloc 啥的。
    agagega
        6
    agagega  
       2022-06-02 10:38:36 +08:00 via iPhone
    如果 Java 里面已占用内存超过这个最大值但是又不能 GC 怎么办?
    CodeCodeStudy
        7
    CodeCodeStudy  
       2022-06-02 10:43:52 +08:00
    PHP 如果是 FPM 的话,脚本执行完毕就释放全部内存了。可以在 php.ini 中设置 memory_limit ,如果不限制,将 memory_limit 设置为-1 ,也可以在代码里使用 ini_set('memory_limit', '1G') 来设置
    qwq11
        8
    qwq11  
       2022-06-02 10:46:03 +08:00 via Android
    据我所知,好像这些语言写的 90%的东西都不需要限制内存,简单搜了下 CLR 好像没有限制内存的选项,剩下 10%可能就是上 cgroups 了吧
    Building
        9
    Building  
       2022-06-02 10:48:40 +08:00   ❤️ 4
    语言没有办法控制内存上限,就好像加法不能限制最大数一样,能限制内存上限的是 runtime
    yazinnnn
        10
    yazinnnn  
    OP
       2022-06-02 10:54:48 +08:00
    就是说非 vm 语言都需要在系统中控制吗?
    像 dart 这种就可以通过虚拟机控制?


    假如说用 rust 或者 go 开发了一个 web 服务,想控制他的内存上限在 200m,只能用系统限制,二进制文件是无法限制的

    这样?

    clr 也不能限制么?
    JYii
        11
    JYii  
       2022-06-02 11:01:55 +08:00   ❤️ 3
    @agagega jvm 会根据 score ,kill 掉占用内存最大的,👴的服务刚被系统干掉
    laowudxf
        12
    laowudxf  
       2022-06-02 11:09:56 +08:00
    Swift 貌似没有参数可以控制内存上限,本来就是指针引用计数来控制内存,该用多少就用多少。我的 Swift 后台服务长时间在 32m 以内。
    SMGdcAt4kPPQ
        13
    SMGdcAt4kPPQ  
       2022-06-02 11:10:29 +08:00 via Android
    CLR 可以限制内存
    docs.microsoft .com/en-us/dotnet/core/runtime-config/garbage-collector#heap-limit
    arischow
        14
    arischow  
       2022-06-02 11:11:37 +08:00
    丢进 Docker 然后 limit ?

    或者使用本身 Docker 所利用的 cgroups ?
    DOLLOR
        15
    DOLLOR  
       2022-06-02 11:21:06 +08:00
    node 的 [--max-old-space-size=] 应该能起到类似功能,比如
    node --max-old-space-size=5120 app.js # Increase limit to 5GB
    cheng6563
        16
    cheng6563  
       2022-06-02 11:25:06 +08:00   ❤️ 1
    @agagega 会在分配内存的时候(如 new XXX)弹出 OOM 异常。
    这里有个巨坑,A 线程分配占用大内存并保持不动,然后可能会 B 线程分配新内存弹出 OOM 异常,然后 B 线程捕获异常打日志,然后打日志的代码也 OOM ,最后整个线程挂掉并且日志文件没日志。完全失去控制。

    生产环境一般会加-XX:+ExitOnOutOfMemoryError 使其 OOM 就直接干掉整个进程直接重启完事。
    jiangwei2222
        17
    jiangwei2222  
       2022-06-02 11:27:32 +08:00
    @kkocdko #5 比起 hook malloc 啥的,直接启一个 docker ,然后限制 docker 容器的内存更合适一点吧。自己 hook 稍不注意就出问题了
    LeegoYih
        18
    LeegoYih  
       2022-06-02 11:30:55 +08:00
    语言层面本身没法限制吧,如果要实现的话可以用虚拟机或者容器,不过如果 OOM 会被 KILL 。
    hbdh5
        19
    hbdh5  
       2022-06-02 11:39:35 +08:00
    @Building 其实如果一定要从语言层面限制也是可以的,比如 rust 或 c++可以自己实现一个超过指定内存就 panic 的内存分配器然后指定为全局内存分配器
    northernlights0
        20
    northernlights0  
       2022-06-02 11:45:34 +08:00
    有虚拟机的语言在虚拟机层面控制,其它的在操作系统层面
    BeautifulSoap
        21
    BeautifulSoap  
       2022-06-02 11:49:34 +08:00 via Android
    内存上限是系统(或虚拟机)控制的不是语言自身
    nothingistrue
        22
    nothingistrue  
       2022-06-02 12:22:27 +08:00
    JVM 的内存上限是由 VM 而不是又运行程序控制的,严格的说它也是由操作系统(只不过是个 VM )而非应用控制的。另外,JVM 能精确控制的只有堆内存,整个 VM 的内存(即 java.exe 进程占用的内存),它也是不精确控制的。
    FrankHB
        23
    FrankHB  
       2022-06-02 12:36:45 +08:00
    @Building 你好歹讲点别的吧,加法?明显语言的语义上不限制上限的麻烦得多以至于几乎没什么语言不限制。只要你用的数据类型明确限制了最大元素,加法还能绕出去?就是任意精度数值,内部表示也受到空间的限制而不可能表示任意大的数;真正没限制最大数的怕就是只有 lazy list 之类的模拟了,你倒是统计下有几个语言这么做了?

    最简单的,C 无符号数直接钦定不溢出,内部表示占用固定大小。只要语言残废到都是类似的玩意儿再在超出实例时禁止翻译就能静态证明不可超出限制了。阉掉了动态分配和递归的 C 类似物也是这样,只不过不方便算出具体上限是多少,一般要凑。
    yolee599
        24
    yolee599  
       2022-06-02 12:46:30 +08:00 via Android
    C:可以自己实现 malloc ,给你多少就只能用多少
    dalabenba
        25
    dalabenba  
       2022-06-02 12:55:01 +08:00 via Android
    应用->内存分配库->系统调用
    从内存分配库的角度看,需要分配库追踪分配的数量,才能做到控制内存上限
    从操作系统角度看,ulimit 可以限制分配虚拟地址的大小,实际物理的占用可能要 cgroup 来做
    不管是什么语言,最终都会调到这两个来,vm 类的语言可能在内存分配库之上还有自己的限制(比如你说的 jvm)
    yazinnnn
        26
    yazinnnn  
    OP
       2022-06-02 13:06:57 +08:00
    graalvm 利用 native-image 构建的二进制文件依然可以用-Xmx 来设置程序运行时的堆内存大小

    那么就表示这个二进制文件仍然包含了一层 jvm,由 jvm 来管理实际程序?
    yazinnnn
        27
    yazinnnn  
    OP
       2022-06-02 13:20:50 +08:00
    搜了一下看到 go 有 SetMaxHeap 函数来对堆内存进行设置,这是自带 gc 的语言的标准库实现
    https://www.jianshu.com/p/4069d1e3d716
    https://groups.google.com/g/golang-codereviews/c/brkajcJ0mhI/m/VyXYtel4BgAJ

    那么 rust 有没有类似功能呢?
    learningman
        28
    learningman  
       2022-06-02 13:57:10 +08:00
    rust 不带 gc ,运行的时候二进制里面只有你的代码。
    你不写一个那就是没有
    Building
        29
    Building  
       2022-06-02 14:04:09 +08:00 via iPhone
    @FrankHB 你先搞清楚什么是语言,什么是数据类型吧。如果 Int 的最大值为 255 是因为一个 Int 只用了 8 个字节,和语言没关系,就好像你定义了 a[10],语言也不会限制你写 a[100],只是这样写会报错,同理你想访问 a[10^100000],一点问题都没有,语言不会也不应该考虑去帮你考虑内存够不够的问题
    timpaik
        30
    timpaik  
       2022-06-02 16:41:40 +08:00 via Android
    @yazinnnn #27 jvm 回收的内存也是程序不用的内存,jvm 大部分情况是定时检测有没有可以回收的内存,而 Rust 不需要 GC 就可以释放这些内存,一旦程序不用就会立即释放。你既然创建了变量申请了内存,又不想让它申请内存,为什么会有这种需求呢
    haoliang
        31
    haoliang  
       2022-06-02 20:10:17 +08:00
    python 可以使用 resources.setrlimit (为啥大家都不提这个 setrlimit ,不会是我审错题了吧?)
    haoliang
        32
    haoliang  
       2022-06-02 20:13:47 +08:00
    当然它实际就是 ulimit ,不过在语言中我们总要对应到方法吧...
    my3157
        33
    my3157  
       2022-06-02 20:57:38 +08:00 via Android
    @westoy cgroups +1 ,如果嫌麻烦,可以用 docker 或者 podman
    2NUT
        34
    2NUT  
       2022-06-02 22:56:51 +08:00
    不带 gc 的语言 在编译期就确定了 内存占用了
    Alphagocc
        35
    Alphagocc  
       2022-06-02 23:32:21 +08:00   ❤️ 1
    @2NUT 了解一下 new malloc 是什么?
    zeni123
        36
    zeni123  
       2022-06-03 05:51:28 +08:00
    人工控制内存使用上限
    FrankHB
        37
    FrankHB  
       2022-06-03 06:47:04 +08:00
    @Building 报错不是限制?
    没兴趣浪费金币仔细科普什么叫 ill-formedness 了。
    8 字节,嗯嗯……
    要不是你这典中典回复成了几个群里的乱窜的表情包,我还真差不多忘了我有回复这楼了……
    Building
        38
    Building  
       2022-06-03 09:41:24 +08:00 via iPhone
    @FrankHB 报错是编译器行为……你不想报错完全可以强行编译,和语言没有关系。计算机理论里内存是无限的就好像数学世界里数是无限的一样。无论用什么语言,本质上都只是再控制指针操作内存,这是计算机的基本原理,如果语言能限制内存使用,就好像说数学坐标轴最大值只能到 1024 一样
    FrankHB
        39
    FrankHB  
       2022-06-03 09:50:44 +08:00
    @Building ?我甚至还要在这科普什么叫 conformance 和数学常识了吗?
    该报错的不报错,不该报错的报错了,那叫 bug ,不管是编译器还是运行时的。决定什么该报错,该报什么错的是 spec 里的规则。写编译器一般没什么能力同时做整个 spec ,所以直接用的语言的 spec ;就算自己写 spec ,不是照抄的,实际上就发明了语言出来。
    内存无限和数学如何明显是你 yy 。都玩那种玩具 model ,那早搞体系结构的就破产了。数学不好请自己补课。数无限?抽象代数我实在不想教,要不你还是先搞清楚比如 C 的无符号数折腾的就是数学上的 modular arithmetic 那套这样的入门经验再说吧。
    bugu1986
        40
    bugu1986  
       2022-06-03 10:36:18 +08:00
    有的语言没有 gc 不需要设置
    Building
        41
    Building  
       2022-06-03 13:43:28 +08:00
    @FrankHB 你扯的什么乱七八糟的东西啊,来来来,最简单的,写一段程序,只要输入一个字符,立刻申请 1gb 的内存放着,别管我用来干什么,你举个例子,哪一门语言的编译器这么牛逼不给过?
    hxndg
        42
    hxndg  
       2022-06-04 00:48:22 +08:00
    hxndg
        43
    hxndg  
       2022-06-04 01:02:44 +08:00
    @FrankHB
    不好意思,刚才不小心敲错了。。。。
    实际上我没太看明白你的意思,可以详细解释下吗?或者指明一些资料?我内存这块的很多认识都是原先从实际工程现看的,可能已经和现在的发展脱节了?
    原先做性能优化,使用 linux 的 hugepage 直接在用户态内存管理的时候就是类似 slab 来做操作,这个控制是算 runtime 做的吗? C 应该不限制这个?另外目前 x64 虚拟内虽然保存了一些高位,但是基本可以认为是无限的?
    hxndg
        44
    hxndg  
       2022-06-04 21:58:16 +08:00
    @FrankHB
    忽然想起来一个,你是说 /proc/pid/limit 下面的资源限制吗?
    t2jk4000
        45
    t2jk4000  
       2022-06-05 00:42:50 +08:00
    @JYii 这个难道不是操作系统 kill 的么
    461da73c
        46
    461da73c  
       2022-06-05 14:50:56 +08:00
    JAVA 真是又慢又费内存。
    JYii
        47
    JYii  
       2022-06-06 09:28:10 +08:00
    @t2jk4000 对,是操作系统,前半句说的有误
    FrankHB
        48
    FrankHB  
       2022-06-23 19:21:04 +08:00
    @Building 所以你也太小看编译器的下限了。
    “申请内存”?你是不是不知道直接不提供给你“申请内存”的实现也符合 ISO C ?你先给我说说你怎么确保一个 strictly conforming 的 C 程序“申请内存”还一定能过?
    顺便,让 int main(){int a;}直接给 stack overflow 都是符合 ISO C 的。你说你见到过的编译器都会过?行,我写个程序判断源代码是不是长这样,如果是就直接给你生成一跑就会挂掉的二进制代码,不是就扔给 gcc ,不也是个符合 ISO C 的实现?(不符直接扔标准条款谢谢。)
    (顺便,int a;不算“申请”内存。)
    所以用得着你个“申请内存”个什么寄玩意儿啊……

    @hxndg 上面举例子过了,用到个自动对象都可以给你当作栈爆了,也是合乎规矩的。即便没什么实现那么不要脸。
    实际上这是 ISO C 比较下限,事实上允许实现随便钦定资源限制,但一点都没说最小限制是什么,只说超过限制 UB 。
    而且这个比“分配内存”特殊在于原则上是没法直接加规则修的,因为 ISO C 抽象机里根本就没调用栈这种东西,自动对象不是被“分配”的。(但显然又要占资源,否则不确保不会爆栈的现有实现都不符合 ISO C 了。)
    ISO C++同理( core lang 里唯一一个提到 stack 的是 stack unwinding )。
    其实这种设计就没什么可移植性。

    /proc/pid/limit 这个倒是比较有实际意义的好例子。不过,这个显示不出语言设计不讲理的地方。
    Building
        49
    Building  
       2022-06-23 20:55:06 +08:00 via iPhone
    @FrankHB 为什么你总是不肯正面回答问题?扯这么多乱七八糟的东西?你就回答具体那一门语言的编译器动态申请内存不让过就行了
    FrankHB
        50
    FrankHB  
       2022-06-23 22:01:13 +08:00
    @Building 我没正面回答么?是不是你看不懂什么叫 ISO C ?
    退一步讲,你连 OP 都不是,我 at 你又不是私信,非得专门喂给你看的所以一定要浅显到连你都看得懂?
    再退一步讲,为什么我有义务回答你经常连 well-formed 都算不上的问题?
    而且你哪来的自信定义什么叫“乱七八糟”,你是很确信在这个问题领域比我更权威咯?
    Building
        51
    Building  
       2022-06-23 22:09:29 +08:00
    @FrankHB 所以呢?快回答啊,哪一门语言不给过?哪一门?说出来啊?承认自己错真的不丢脸,但是你气急败坏的样子真的很搞笑
    FrankHB
        52
    FrankHB  
       2022-06-23 22:27:46 +08:00
    @Building 睁眼瞎,“ISO C”都不知道?还是要说 ISO/IEC 9899 ?就算谭×也告诉过所谓的“C 语言”的学名是什么吧。还是非得拉上快没什么人鸟的 K&R C ?你能出多少经费要我考古吗?
    你表演丈育症状就算了,非得表现常识有罪丈育没错就很欠扁诶···
    Building
        53
    Building  
       2022-06-23 22:39:48 +08:00
    @FrankHB 快回答我啊,语言,哪一门语言,哪一门?名字是什么?你为什么说通用标准协议?你用通用标准协议写程序吗?还是你自己发明了一门语言?快,语言名字,我马上写给你看能不能过
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   901 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 22:11 · PVG 06:11 · LAX 14:11 · JFK 17:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.