V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
smallyu
V2EX  ›  程序员

为什么 Go 语言可以交叉编译,打包出目标平台二进制, Java 不行?

  •  
  •   smallyu · 2020-07-15 09:13:02 +08:00 · 7241 次点击
    这是一个创建于 1352 天前的主题,其中的信息可能已经有所发展或是发生改变。

    好像很多语言的程序包执行都需要相应的环境,除了脚本类的,Java 这种需要编译的,好像经常也是 java -jar abc.jar 这种,而 go 语言能直接编译出不依赖 go 环境的包。可以帮忙提点一下吗盆友们,关于这个问题,应该往哪方面去了解?

    36 条回复    2020-07-16 01:33:33 +08:00
    seers
        1
    seers  
       2020-07-15 09:16:07 +08:00
    解释型编译型?不过 Java 也要编译但是还是依赖 jvm
    HiShan
        2
    HiShan  
       2020-07-15 09:16:26 +08:00
    graalvm 了解一下
    sulinehk
        3
    sulinehk  
       2020-07-15 09:17:45 +08:00 via Android   ❤️ 1
    可以进行自动垃圾回收的语言都需要一个运行时环境,只不过 Go 是把这个运行时打包到二进制文件里,而 Java 显示使用这个运行时。
    ChanKc
        4
    ChanKc  
       2020-07-15 09:18:35 +08:00 via Android
    aot 和 jit ?
    lower
        5
    lower  
       2020-07-15 09:20:29 +08:00
    操作系统原理、编译原理、计算机组成原理
    monkeyWie
        6
    monkeyWie  
       2020-07-15 09:22:12 +08:00
    graalvm +1,不过静态编译限制比较多,反射类加载就不好用了
    BingoXuan
        7
    BingoXuan  
       2020-07-15 09:28:26 +08:00   ❤️ 7
    java 编译出来的是通用的字节码,扔到不同平台的 jvm 内就能运行,实现 compile once, run(debug?) everywhere 。
    go 编译出来的是不同平台的机器码,不同平台只能运行对应二进制文件,实现 code once, compile for everywhere
    sonxzjw
        8
    sonxzjw  
       2020-07-15 09:40:15 +08:00
    1.java 也可以打包成二进制执行程序,要找工具,有不少缺点;
    2.java 的创始人的层面就是这样的理念,用 jvm ;

    其实这些很多都是跟语言创始人的理念、多方面考虑而定的。
    zjsxwc
        9
    zjsxwc  
       2020-07-15 09:43:43 +08:00
    只要 jvm 在目标平台可以跑就行,大不了发布的时候把 jvm 也带上不就好了
    tlday
        10
    tlday  
       2020-07-15 09:46:44 +08:00   ❤️ 7
    Java 最初就是作为编写放进一些家电设备中的嵌入式编程语言立项的,在这种条件下,你要求这些家电设备内置一个桌面级运行环境是很奢侈的,那可是 1991 年,桌面级运行环境作为嵌入式设备的平台?那个时候还不是这三家独大,有各种奇奇怪怪的系统和平台。相反,你制订一个标准让对应的硬件平台厂商去实现,要更符合那个时代的主旋律。
    而且将 runtime 直接放进应用程序这种想法在当时的带宽条件下是个正常人都不会有的。大家肯定还记得在智能手机出现以前,一些支持 J2ME 平台的手机,一个几百 k 的 jar 文件中能有多丰富的游戏内容。如果你把 runtime 也打包进去,那是不可能那么小的。你看 Windows 到现在还在发布.Net
    你不能现在只看得到 JavaSE 和 JavaEE 就忽略 J2ME 才是 Java 最早的初衷。
    tlday
        11
    tlday  
       2020-07-15 09:47:30 +08:00
    独立的.Net runtime 到操作系统。
    dakb
        12
    dakb  
       2020-07-15 09:51:58 +08:00
    因为 java 是跑在虚拟机上的语言。go 是直接编译成目标文件的语言。
    DJQTDJ
        13
    DJQTDJ  
       2020-07-15 10:18:33 +08:00
    建议楼主私信 James Gosling,我想如果他有时间的话,应该会告诉楼主为什么把
    https://twitter.com/errcraft
    janxin
        14
    janxin  
       2020-07-15 10:30:10 +08:00
    不要这样,Java 其实也可以的,GraalVM 了解一下
    Rwing
        15
    Rwing  
       2020-07-15 10:40:14 +08:00
    .NET 欢迎您
    libook
        16
    libook  
       2020-07-15 10:50:39 +08:00   ❤️ 5
    不知道什么课程里会包含这些知识,计算机导论?感觉只要是科班出身的都自然而然地了解这个。

    大学课程里最初是会将编程语言分为:
    机器语言:二进制指令
    低级编程语言:汇编语言
    高级编程语言:C 、C++、Java 等等

    然后高级编程语言大体上又可以分为:
    编译型语言:C 、C++、Java 等
    解释型语言:JavaScript 、Python 、PHP 等

    编译型语言又可以分为:
    直接编译成平台机器码的语言:C 、C++、Go 等
    编译成虚拟机机器码的语言:Java 、C#、WebAssembly 等

    以上只代表各个语言的常规使用方式,实际上语言只是语言,设计不同的编译和运行机制,可以让一门语言以不同的方式来操作计算机运行,比如使用特定的编译器可以将 Java 直接编译成机器码,不依赖 Java 运行时就可以运行,C 也可以编译成虚拟机机器码,在虚拟机上运行。

    Java 的可执行程序本身不携带 Java 运行环境,这个其实是 Java 的设计初衷,以及其最大的卖点:“Write once, run everywhere”。因为早先的编程语言都需要编译成对应平台的机器码才能被正确运行,比如想在电脑上运行就编译成台式机平台的程序文件,想在手机上运行就编译成手机平台的程序文件,而如果电脑和手机采用的 CPU (指令集)不一样的话,对应电脑平台的可执行文件无法在手机上运行,而且编译成不同平台的程序文件很可能需要改动大量代码。(这个就不展开介绍了,想了解可以去学习一下计算机组成原理和汇编语言。)然后 Java 率先实现了写一份代码、编译成一个可执行文件,可以在任何被 Java 运行环境支持的设备上运行,Sun 公司负责开发出支持各个设备的 Java 运行环境。这对于需要程序支持多个硬件平台的开发者来说,几乎完全免除了兼容多个设备需要做的大量工作(至少在当时是)。
    passerbytiny
        17
    passerbytiny  
       2020-07-15 10:53:46 +08:00 via Android
    Go 是用来替代 C ( C ++)的,为何要跟 Java 比较。
    Kilerd
        18
    Kilerd  
       2020-07-15 11:37:56 +08:00
    @passerbytiny #17 Go 用来替代 C ?
    dhssingle
        19
    dhssingle  
       2020-07-15 11:57:14 +08:00
    @passerbytiny #17 因为实际跑起来,效率还不如 C# 和 Java,拿什么去替代 C 。
    wysnylc
        20
    wysnylc  
       2020-07-15 12:12:28 +08:00
    Java 可以,只是不建议用
    Go 是只能打包成二进制文件,没有其他选择哦
    jizhihaoSAMA
        21
    jizhihaoSAMA  
       2020-07-15 12:23:29 +08:00
    @passerbytiny 替代 C cpp 写服务端吧,其他的替代不了
    koebehshian
        22
    koebehshian  
       2020-07-15 13:50:50 +08:00
    编程语言只规定了语法,编译器或解释器是对编程语言的实现,一种语言可以有多种实现。
    DoctorCat
        23
    DoctorCat  
       2020-07-15 13:58:25 +08:00
    抛开原理,说个分发方面:
    Go 把依赖都打包在一个可执行体里了(编译后都是机器码不需要 VM,runtime 部分尺寸相对 Java 运行时要小得多,分发起来轻便)
    Java 有一整套的 VM 依赖和其他框架的库依赖(编译后是字节码必须在 JVM 上执行,依赖尺寸太大,所以分开了好。分发起来应用与 VM 独立比较好)。
    c2const
        24
    c2const  
       2020-07-15 14:05:58 +08:00 via iPhone
    go 编译后其实带一个很小的运行库,不过是集成在一起了,和 java 在语言设计之初就不一样。
    Java 也有 aot 编译,不过因为语言设计之初的目的,而且现在 java 也太臃肿,做 aot 编译的项目和公司基本都凉了,或者很久没更新了。
    最新的商业软件好像是可以支持到 jdk1.8,前几年那公司也倒闭了。

    技术原理大概就是

    0,把与 jvm 无关的逻辑代码转成汇编(现在有 llvm 方便很多),
    1,与虚拟机耦合不深的 native 方法(比如数组拷贝),一般是重新实现一份
    2,与虚拟机耦合深的方法(比如获取虚拟机启动时间),一般做法还是需要启动一个最小虚拟机
    3,特有语法特性,比如 反射、动态改字节码、jvm 上其它语言的函数式编程……都是大坑

    不过计算机的事,没什么是加中间层不能解决的。
    huiyifyj
        25
    huiyifyj  
       2020-07-15 14:07:28 +08:00
    @passerbytiny #17 你说 rust 替代 c/c++我还行,go 就算了。
    huiyifyj
        26
    huiyifyj  
       2020-07-15 14:08:03 +08:00
    @huiyifyj #25
    行 => 信
    c2const
        27
    c2const  
       2020-07-15 14:20:32 +08:00 via iPhone
    @huiyifyj 仅个人感觉,go 是抢 c/c++的服务端市场。rust 微软再推,抢 c/c++操作系统、内核组件、安全是为了防止内存泄露相关的漏洞利用,主要还是安全领域相关的吧
    个人不太喜欢 go 语法,c/c++真香:)
    gz911122
        28
    gz911122  
       2020-07-15 14:32:13 +08:00
    java 也可以的 graalvm 了解一下

    先问是不是再问为什么
    liuxey
        29
    liuxey  
       2020-07-15 14:34:46 +08:00
    "而 go 语言能直接编译出不依赖 go 环境的包"

    Go 把运行环境编译进了二进制包!
    flynaj
        30
    flynaj  
       2020-07-15 14:34:50 +08:00
    go 出生比较晚,以前一些没解决的需求不解决,还有更好的性能。多核心支持的话,不会有人用的。
    sunziren
        31
    sunziren  
       2020-07-15 14:35:43 +08:00
    同意楼上的,我也有这个疑问,建议你直接问发明 java 的那个人。
    locy
        32
    locy  
       2020-07-15 17:13:37 +08:00
    java 文件是编译成字节码,字节码!=机器码,字节码是在虚拟机上执行的。
    Tink
        33
    Tink  
       2020-07-15 17:33:59 +08:00
    看一下 编译原理
    tairan2006
        34
    tairan2006  
       2020-07-15 19:02:35 +08:00
    时代不一样了,云时代 go 确实有部署优势
    chihiro2014
        35
    chihiro2014  
       2020-07-15 19:15:00 +08:00
    Go 就算了。。。
    systemcall
        36
    systemcall  
       2020-07-16 01:33:33 +08:00 via Android
    时代不一样,Java 出来的那个时代,CPU 指令集和 OS 都五花八门,迫切的需要一个不用重新编译就可以跨平台的系统。当时许多设备的内存是以 KB 来计算的,用 XiP 来运行。0 几年也是这样。以前 Java 用的多的地方基本上就是现在安卓用的多的地方
    Java 编译成二进制是可以的,针对平台优化也是可以的,但违背了 Java 的初衷,不过现在也没多少人提了吧。安卓里面用户也不能够直接运行 j2me 应用了。现在的指令集和 OS 就那几个,真是方便
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1148 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 18:32 · PVG 02:32 · LAX 11:32 · JFK 14:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.