到目前为止,所有操作系统都是用C/C++编写的,而没有用Java编写的。虽然有很多Java应用程序,但却没有操作系统。为什么呢?
到目前为止,所有操作系统都是用C/C++编写的,而没有用Java编写的。虽然有很多Java应用程序,但却没有操作系统。为什么呢?
由于我们已经有了操作系统,因此 Java 并不是设计用于在裸机上运行的,但这并不是一开始看起来那么大的障碍。正如 C 编译器提供内置函数编译成特定指令一样,Java 编译器 (或 JIT,在这个上下文中没有实际区别) 也可以做同样的事情。处理 GC 和内存管理器之间的交互也有点棘手,但是它是可行的。结果就是一个 95% 由 Java 构成且准备运行 jar 的内核。接下来呢?
现在是编写操作系统的时候了。设备驱动程序、文件系统、网络堆栈等所有其他使计算机能够完成任务的组件。Java 标准库通常会大量依赖系统调用来完成重活,既因为必须如此,也因为“运行计算机很麻烦”。例如,写入文件涉及以下层次结构(至少我不是操作系统专家,所以我肯定会错过一些东西):
所有这些都必须正常运行,并在十几个线程访问磁盘时保持性能良好,因为磁盘本质上是一堆共享可变状态。
最后,你得到了 Linux,除了它的功能和性能没有被充分投入外,它只能运行 Java。可能你从一个单一的地址空间和没有内核/用户空间区别中获得了性能提升,但是这种收益不值得投入的努力。
在一个特定语言的操作系统中有一种情况是有意义的:虚拟机。让底层操作系统处理计算机运行的困难部分,让租户操作系统处理将虚拟机转换为执行环境的任务。 BareMetal 和 MirageOS 遵循这个模型。那么,为什么要这样做而不是使用Docker呢?这是一个好问题。
使用Java的主要优势之一是它抽象了许多通常您不需要关心的低级细节。这些细节在构建操作系统时是必需的。所以尽管您可以绕过这个问题用Java编写操作系统,但会有很多限制,并且您将花费大量时间与语言及其初始设计原则进行斗争。
对于操作系统,你需要在非常底层的地方工作。而在Java中这是一种痛苦。例如,你需要使用无符号数据类型,但Java只有有符号数据类型。你需要有 struct
对象,它们具有驱动程序期望的内存对齐方式(并且没有像Java为每个对象添加的对象标头)。
即使是Java本身的关键组件也不再是用Java编写的。
这绝不是暂时的事情。越来越多的东西会被重写为原生代码以获得更好的性能。HotSpot VM为性能关键的原生代码添加了 "intrinsics",并且正在努力降低原生调用的总成本。
例如JavaFX:它比AWT/Swing快得多的原因是因为它包含/使用大量的本机代码。它依赖本机代码进行渲染,并且如果你添加 "webview" 浏览器组件,它实际上使用webkit C库提供浏览器。
Java确实做了很多很好的事情。它是一种结构良好的语言,拥有一个极好的工具链。Python写起来更加简洁,但其工具链却很混乱,例如重构工具令人失望。Java的优点在于能够在运行时优化多态性。C++编译器需要进行昂贵的虚拟调用,因为在编译时不知道将使用哪个实现,而Hotspot则可以通过侵入式编写代码来获得更好的性能。但是对于操作系统来说,你并不需要这么多。你可以承受手动优化调用站点和内联。
这个回答并不打算详细阐述任何问题,但我想分享一下我的思考(这是一个非常广泛的主题)。
尽管在理论上可以使用纯 Java 编写某些操作系统,但实际上存在一些使得这项任务极为困难的实践问题。主要问题在于目前不存在一种最新且可靠的 Java 编译器能够将 Java 编译为字节码。因此,在我所知道的范围内,目前没有现有工具可以使得从头开始编写整个操作系统变得可行。
Java 被设计成在某些 Java 虚拟机的实现中运行。存在着 Windows、Mac、Linux、Android 等平台的实现。该语言的设计强烈依赖于 JVM 的存在,并期望运行时 JVM 会进行一些魔术操作(例如垃圾回收、即时编译器、反射等)。这很可能是为什么不存在这样的编译器的部分原因:所有这些功能都应该被编译成字节码吗?这是可能的,但我认为在这个时候这将会很困难。甚至 Android,其 SDK 完全基于 Java,也在 Linux 内核上运行 Dalvik(JVM 的一个版本,支持语言的子集)。