与 CPython 等其他运行时相比,究竟是什么让 JVM(尤其是 Sun 的实现)运行缓慢?我的印象是,这主要与大量库是否需要加载有关,但这似乎不需要 10 年的时间来解决。
想一想,JVM 启动时间与 Windows 上的 CLR 相比如何?Mono 的 CLR 怎么样?
更新:我特别关注 Unix 中常见的链接在一起的小型实用程序的用例。Java 现在适合这种风格吗?无论 Java 产生什么启动开销,它是为每个 Java 进程加起来的,还是仅在第一个进程中才真正体现出来?
与 CPython 等其他运行时相比,究竟是什么让 JVM(尤其是 Sun 的实现)运行缓慢?我的印象是,这主要与大量库是否需要加载有关,但这似乎不需要 10 年的时间来解决。
想一想,JVM 启动时间与 Windows 上的 CLR 相比如何?Mono 的 CLR 怎么样?
更新:我特别关注 Unix 中常见的链接在一起的小型实用程序的用例。Java 现在适合这种风格吗?无论 Java 产生什么启动开销,它是为每个 Java 进程加起来的,还是仅在第一个进程中才真正体现出来?
以下是维基百科对这个问题的看法(附有一些参考资料)。
似乎大部分时间只是从磁盘加载数据(类)(即启动时间受 I/O 限制)。
在我的机器上使用 1.6 (Java 6) 客户端 JVM 运行一个简单的 Java 应用程序似乎是即时的。Sun 已尝试调整客户端 JVM 以加快启动速度(客户端 JVM 是默认设置),因此如果您不需要大量额外的 jar 文件,那么启动应该很快。
如果您使用 Sun 的 HotSpot for x86_64(64 位编译),请注意当前实现仅在服务器模式下工作,也就是说,它预编译加载的每个类并进行完全优化,而 32 位版本还支持客户端模式,这通常会推迟优化并仅优化 CPU 密集程度最高的部分,但启动时间更快。
参见例如:
话虽如此,至少在我的机器上(Linux x86_64 和 64 位内核),32 位 HotSpot 版本支持客户端和服务器模式(通过 -client 和 -server 标志),但默认为服务器模式,而 64 位版本仅支持服务器模式。
这实际上取决于您在启动期间正在做什么。如果你在我的机器上运行 Hello World 应用程序需要 0.15 秒。
但是,Java 更适合作为客户端或服务器/服务运行,这意味着启动时间不如连接时间(约 0.025 毫秒)或往返时间响应时间(<< 0.001 毫秒)重要。
有几个原因:
jar
要加载的我不确定 CLR,但我认为它通常更快,因为它会为下次缓存本机版本的程序集(因此它不需要 JIT)。CPython 启动速度更快,因为它是一个解释器,而 IIRC 不执行 JIT。
除了已经提到的事情(加载类,特别是从压缩的 JAR 中);在 HotSpot 编译常用字节码之前以解释模式运行;和 HotSpot 编译开销,JDK 类本身也完成了相当多的一次性初始化。许多优化都是为了支持运行时间较长的系统,而这些系统的启动速度不是那么重要。
至于 unix 风格的流水线:您当然不想多次启动和重新启动 JVM。这不会是有效的。工具链应该发生在 JVM 中。这不能轻易地与非 Java Unix 工具混合,除非从 JVM 中启动这些工具。
与在 C 或 C++ 中发现的不太丰富的系统相比,所有具有丰富类型系统(如 Java 或 CLR)的 VM 都不会是即时的。这主要是因为在 VM 中发生了很多事情,很多类被初始化并且是正在运行的系统所需要的。初始化系统的快照确实有帮助,但将图像加载回内存等仍然需要花费。
一个简单的 hello world 风格的一个带有 main 的班轮类仍然需要加载和初始化很多东西。验证类需要大量的依赖关系检查和验证,所有这些都需要时间和执行许多 CPU 指令。另一方面,C 程序不会执行任何这些操作,而是会执行一些指令,然后调用打印机函数。