为什么 Java 的调试 Hot Swap 仅限于方法内更改?

Why is Java's debugging Hot Swap limited to intra-method changes?

我已经完成 hot deployment tutorial 并且有效。 但我对限制(第 3 点)有疑问,即

热部署仅支持方法实现中的代码更改。如果添加新的class或新的方法,仍然需要重启。

基本上,如果我对现有方法进行更改但在添加方法或 class.

时需要重新启动服务器,这就是为什么我们不需要重新启动服务器的原因

我对它的工作原理的理解:- 当我对现有方法进行更改或引入新方法时,Eclipse 会将文件放置在正确的位置 在网络服务器下。如果 class 已经在 perm gen space 中被 classloader 加载,它将从 permgen space 卸载它并在不重启服务器的情况下在内部加载新的,以便新的变化(字节码)被反映出来。那是对的吗 ?

如果是,为什么热部署不适用于新方法和新 class 文件?

其中的推理相当复杂,而且只有对 JVM 及其管理内存方式了如指掌的人才完全了解。这里有一个不错的解释:Java HotSwap Guide(尽管它实际上是 JRebel 产品的广告)- 滚动到标题为 为什么 HotSwap 仅限于方法体的部分?.

要点:有两个主要因素阻止 HotSwap 处理对 classes 的结构更改:JIT 和内存分配。

JVM 中的 JIT(即时)编译器在加载 classes 和 运行 几次后优化字节码,基本上内联许多调用以提高性能。在 class 签名和结构可以更改的环境中安全有效地实施该功能将是一项重大挑战。

如果允许更改 class 结构,则其他问题围绕内存管理会发生什么。 JVM 必须修改 classes 的现有实例,这意味着将它们重新定位到堆存储的其他部分。更不用说必须自己重新安置 class objects。 JVM 的内存管理已经非常复杂且高度优化;此类更改只会增加复杂性并可能降低 JIT 编译器的性能(并可能导致其他错误)。

我认为可以有把握地假设 JVM 工程师不愿意在支持此功能所需的性能和错误足迹之间进行权衡。这就是 JRebel 等产品应运而生的原因。

附带说明一下,规范本身是 not limited

碰巧一些可用的实现,包括无处不在的 Reference Implementation,是有限的。

连接到远程 VM 后,您可以检查它是否允许 add methods or redefine classes

如果你 运行 你的 java 在 smalltalk vm 上,你可以。 Smalltalk 基本上一直在这样做,这也是 Smalltalkers 倾向于将调试器驱动开发作为测试驱动开发的一种高级形式的原因之一。 Smalltalk vms 执行所需的内存数据结构清理。在 Eliot Miranda 的 Spur(用于 Squeak、Pharo 和 Cuis)和 Gemstone 中,这是懒惰完成的,否则您可能必须等待所有对象被迁移。参考实现 java vm 可能比 a.t.m 运行 java 上的任何 smalltalk vm 有更多的优化。

E-Riz提供的答案已经很好的解释了为什么标准的Java HotSwap技术只支持对现有方法的修改,而不是增加新的class或方法classes.

但是,正如相关 SO discussion 中所述,您实现的热插拔级别取决于您使用的工具链。因此,如果您最终添加了 JRebel 插件,即使添加了新方法和 classes,您也​​可以执行热交换。

还有一个项目:Hot Swap Agent - this is typically a java agent that can be used to run your Java container and you can activate it using a couple of command line parameters (as mentioned in the quickstart).