V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
abcbuzhiming
V2EX  ›  Go 编程语言

请教, Go 是如何实现如此夸张的低的内存占用的?

  •  1
     
  •   abcbuzhiming · 2019-07-29 11:09:47 +08:00 · 13183 次点击
    这是一个创建于 1704 天前的主题,其中的信息可能已经有所发展或是发生改变。
    同样是带有 GC 的语言,Go 的内存占用也太低了点,国外的测试里,同样的功能,Java 都吃到接近 1GB 内存的时候,Go 就十几 MB 的占用;就算不和“家里开矿才能用”的 Java 比,和新锐的 dotnet core 比也有好几倍的差距。我没想明白的是,都是带 GC 的语言,凭什么 Go 就能占这么低的内存?
    37 条回复    2021-07-25 15:27:27 +08:00
    emeab
        1
    emeab  
       2019-07-29 11:12:38 +08:00
    go 编译时直接转到机器码
    neoblackcap
        2
    neoblackcap  
       2019-07-29 11:18:00 +08:00   ❤️ 1
    jit 需要内存。至于相同的功能这个说法我表示怀疑。
    GC 其实跟内存用多少关系不大。
    hoyixi
        3
    hoyixi  
       2019-07-29 11:18:58 +08:00
    java 首先得要个 JVM
    chenqh
        4
    chenqh  
       2019-07-29 11:20:34 +08:00 via Android
    蛇框架?
    chenqh
        5
    chenqh  
       2019-07-29 11:20:44 +08:00 via Android
    什么框架?
    rrfeng
        6
    rrfeng  
       2019-07-29 11:23:06 +08:00
    1. JVM 本身,带 VM 的语言天然就有开销
    2. 设计原因,一个整数类型 Java 里包装了多少层?
    3. 历史包袱,同样功能,Java 可能引入了很多实际上用不到的代码。而 Go 比较年轻,自带库都比较精简。
    micean
        7
    micean  
       2019-07-29 11:33:19 +08:00
    啥测试? java 也没这么夸张吧
    reus
        8
    reus  
       2019-07-29 11:34:32 +08:00   ❤️ 4
    java 是虚拟机,天然就多占内存,再加上没有值类型,很多数据结构都不是紧凑布局的

    .net core 同理

    go 的自动 GC 相对于非自动 GC,多使用的内存主要是 GC bitmap,这部分是 2bit 对应堆里的 64bit,也就是 512GB 的堆全分配满的话,GC bitmap 就会有 16GB,三十二分之一的 overhead。

    另外,GC 算法不同,占内存也会不同。会复制对象的 GC,在复制过程里就需要占用额外的内存。java 的 CMS, G1 都是 copying GC。zgc 暂时不做复制。

    还有个影响因素是向 os 申请页和释放页回 os 的策略。如果虚拟机选择一开始就申请很大的内存,那占用自然高。释放慢,也会高。go 不会预先申请很大的内存,释放页也比较积极,所以内存占用相对就低。
    VDimos
        9
    VDimos  
       2019-07-29 12:04:21 +08:00 via Android
    Java 特性那么多,runtime 肯定比 go 费时费内存啊。而且 java 还有层 jvm。java 还有它那........个无穷无尽的调用。。。
    LokiSharp
        10
    LokiSharp  
       2019-07-29 12:10:30 +08:00
    你确定 Go 写得内个东西功能和 Java 的一样?
    lizhuoli
        11
    lizhuoli  
       2019-07-29 12:13:41 +08:00 via iPhone
    GC 和内存占用大小关系不大,主要是影响分配和回收的性能。对内存影响大的主要是 JVM,Go 压根没有 VM,不需要这一层来做额外的解释和执行内存占用。这是两个东西
    abcbuzhiming
        12
    abcbuzhiming  
    OP
       2019-07-29 12:32:26 +08:00
    @emeab 这个理由。。。java 和 dotnet core 是可以强行用 jit 生成机器码的,但是也没见到内存降低多少


    @hoyixi 查了一下 Go 确实没有 virtual machine,但是一个虚拟机的差别有这么大吗?

    @chenqh 无框架,看我下面给的链接

    @micean
    https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/go.html
    看这个测试,绝大部分情况下 Go 的内存占用都吓人的低
    LokiSharp
        13
    LokiSharp  
       2019-07-29 12:43:35 +08:00
    @abcbuzhiming #12 看起来内存占用差不多啊 Java 虚拟机初始化了差不多 30-40MB,你看 Go CPU 占用都比 Java 高。感觉是默认的 GC 频率比较高吧
    abcbuzhiming
        14
    abcbuzhiming  
    OP
       2019-07-29 12:47:01 +08:00
    @LokiSharp 你确定你看过了,那个连接里出了 reverse 这一项,其它的项目 java 的内存占用起码都是 go 的几倍起
    realpg
        15
    realpg  
       2019-07-29 12:54:30 +08:00
    不论什么 JIT 的问题
    golang 出来的是原生程序,还是静态链接的
    还是跟 C/C++ 静态链接的进行一下对比吧

    且不说那些技术的东西

    你执行一个 java 程序
    java -jar xxx
    或者
    java xxx.class

    执行的这个 java 本身就要吃很多内存不是……
    troywinter
        16
    troywinter  
       2019-07-29 12:58:14 +08:00   ❤️ 3
    都是 trade off,做过 jvm 的优化就知道了,没什么 go 的方式就优于 java,以大部分人写的代码那点水平,还不如让 java 虚拟机优化的性能。大多数人用 go 写出了 python 的性能。

    内存占用低,不代表性能强,只有内存的数据结构 layout 会和性能相关,和 cpu cache,tlb,llc 相关。我曾经优化过 java 服务,各种指标都大大超过了 native c++的速度,就是得益于 jvm 提供的各种优化,内存也是可以被优化的,但只有你有相对而言足够的利益驱使去做时才值得,如果内存占用在业务领域根本不重要,那有什么意义呢?

    go 和 java 的语言设计思路不一样,go 解决的是谷歌这种级别的大规模工程问题,java 解决的是应用跨平台的问题,两者不是对立关系,哪个适合就用哪个。
    LokiSharp
        17
    LokiSharp  
       2019-07-29 12:58:19 +08:00
    @abcbuzhiming #14
    regex-redux
    source secs mem gz busy cpu load
    Go
    29.20 399,668 802 61.29 71% 55% 37% 47%
    Java
    10.48 645,680 740 31.62 72% 87% 74% 68%
    binary-trees
    source secs mem gz busy cpu load
    Go
    25.25 374,780 1013 87.65 87% 88% 86% 86%
    Java
    8.28 907,060 835 27.59 86% 90% 80% 77%

    额。。。哪你咋不说 Go 的运行时间是 Java 的几倍呢。。。
    LokiSharp
        18
    LokiSharp  
       2019-07-29 13:04:41 +08:00
    这两个例子。。。Java 的内存使用是 Go 翻倍但是运行时间却是 Go 的三分之一,综合算下来资源使用并不比 Go 高
    rrfeng
        19
    rrfeng  
       2019-07-29 13:09:43 +08:00 via Android   ❤️ 5
    楼上优化 Java 达到了 native c++ 代码的速度:请问 c++ 是与你同等领域经验的工程师优化过的吗?
    reus
        20
    reus  
       2019-07-29 13:16:21 +08:00
    @LokiSharp regex-redux 慢,是因为用到了 cgo。binary trees 慢,是因为 go 的 GC 比 java 的更频繁,消耗 cpu 更多。基本上 GC 多的程序,go 都比 java 慢,因为 go 偏向低延迟,而不是高吞吐
    reus
        21
    reus  
       2019-07-29 13:18:26 +08:00
    @LokiSharp 看 busy 指标,这几个程序里 go 都比 java 高,就是 GC 的消耗多
    niubee1
        22
    niubee1  
       2019-07-29 13:18:44 +08:00
    JVM 你要是不弄块上 G 的内存来跑的话慢得要死
    micean
        23
    micean  
       2019-07-29 13:20:41 +08:00
    我把 binary-trees 跑了一次,不带参和带参数-Xmx500m -Xms500m,时间差不多,只是带参的 ygc 次数是不带参的 3 倍。所以只是 gc 策略问题。
    当然 java 占用内存肯定还是比 go 要多一些
    bequt
        24
    bequt  
       2019-07-29 13:21:26 +08:00
    前段时间还有个 vlang,那个内存更低
    dhssingle
        25
    dhssingle  
       2019-07-29 14:07:27 +08:00
    LokiSharp
        26
    LokiSharp  
       2019-07-29 14:07:51 +08:00 via iPhone
    @reus 为了内存占用消耗这么多 cpu 我觉得划不来😹😹😹
    reus
        27
    reus  
       2019-07-29 14:39:43 +08:00
    @LokiSharp 主要是还没有分代,有了分代,GC 可以少消耗一点 CPU。而且主要目的是降低延迟,而不是降低内存占用,现在 go 的 GC 的暂停时间可以低于 0.5ms
    sunwei0325
        28
    sunwei0325  
       2019-07-29 16:30:38 +08:00
    jvm 的线程栈 Xss 一般都是写死的 1-2M, go 的 goroutine 栈是动态的, 一般 2K 起
    BBCCBB
        29
    BBCCBB  
       2019-07-29 16:34:37 +08:00
    Jvm 默认会一次性申请一个大内存块, 比如你设置了-Xms1G,那就会一次性申请 1G,

    默认好像是物理内存的 3/8....
    stevenkang
        30
    stevenkang  
       2019-07-29 16:55:53 +08:00   ❤️ 1
    甲方:我这里有一个需求,评估一下多久能完成?

    18 岁的程序猿:最多五天,尽量三天,最快一天(分分钟开发好,年少轻狂,什么包袱都没有)
    20 岁的程序猿:算上测试这些,预计十五天(改一改 bug,修一修代码)
    25 岁的程序猿:设计、开发、测试,预计三十天(流程规范、顺便摸鱼)
    30 岁的程序猿:调研、设计、评估、开发、测试、交付,预计两个月(启动开发之前先评估成本)

    所以,你说 java 这种嵌套十八层的语言,内存需要多少呢?
    wysnylc
        31
    wysnylc  
       2019-07-29 18:59:43 +08:00
    @troywinter #16 有理有据令人信服
    dodo2012
        32
    dodo2012  
       2019-07-29 19:06:36 +08:00   ❤️ 1
    rust 更低,
    5200
        33
    5200  
       2019-07-29 21:06:05 +08:00
    没人注意到楼主的头像吗??
    hangszhang
        34
    hangszhang  
       2019-07-29 23:47:50 +08:00
    我是不信有这么大的差距
    wenzhoou
        35
    wenzhoou  
       2019-07-30 06:56:25 +08:00 via Android
    @5200 头像怎么放大了看?
    no1xsyzy
        36
    no1xsyzy  
       2019-07-30 11:02:12 +08:00
    @abcbuzhiming JIT 不是内存占用更高了?内存里除了运行时还需要载一个编译器,外加字节码和机器码两套码。
    zoharSoul
        37
    zoharSoul  
       2021-07-25 15:27:27 +08:00
    Java 默认是空间换时间
    golang 更倾向于小内存占用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3233 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:08 · PVG 20:08 · LAX 05:08 · JFK 08:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.