java 是什么让热部署成为“难题”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/660437/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 13:17:38  来源:igfitidea点击:

What makes hot deployment a "hard problem"?

javajvmhotdeploy

提问by Andrey Fedorov

At work, we've been having a problem with "PermGen out of memory" exceptions, with the team lead deciding it was a bug in the JVM - something related to hot-deployment of code. Without explaining many details, he pointed out that hot deployment is a "hard problem", so hard that even .NET doesn't do it yet.

在工作中,我们遇到了“永久代内存不足”异常的问题,团队负责人认为这是 JVM 中的错误 - 与代码的热部署有关。他在没有解释很多细节的情况下指出,热部署是一个“难题”,难到连.NET 都没有做到。

I found a lot of articles explaining hot deployment from the bird's-eye-view, but always lacking technical details. Could anyone point me to a technical explanation, and explain why hot deployment is "a hard problem"?

找了很多从鸟瞰角度解释热部署的文章,但总是缺乏技术细节。谁能指出我的技术解释,并解释为什么热部署是“一个难题”?

回答by Eddie

When a class is loaded, various static data about the class is stored in PermGen. As long as a live reference to this Class instance exists, the class instance cannot be garbage collected.

当一个类被加载时,关于该类的各种静态数据存储在 PermGen 中。只要对这个 Class 实例的实时引用存在,就不能对这个 Class 实例进行垃圾回收。

I believe that part of the problem has to do with whether or not the GC should remove old Class instances from perm gen, or not. Typically, every time you hot deploy, new class instances are added to the PermGen memory pool, and the old ones, now unused, are typically not removed. By default, the Sun JVMs will not run garbage collection in PermGen, but this can be enabled with optional "java" command arguments.

我认为部分问题与 GC 是否应该从 perm gen 中删除旧的 Class 实例有关。通常,每次热部署时,新的类实例都会添加到 PermGen 内存池中,而现在未使用的旧类实例通常不会被删除。默认情况下,Sun JVM 不会在 PermGen 中运行垃圾收集,但这可以通过可选的“java”命令参数启用。

Therefore, if you hot deploy enough times, you will eventually exhaust your PermGen space.

因此,如果热部署次数足够多,最终会耗尽 PermGen 空间。

If your web app does not shut down completelywhen undeployed -- if it leaves a Thread running, for example -- then all of the Class instances used by that web app will be pinned in the PermGen space. You redeploy and now have another whole copy of all of these Class instances loaded into PermGen. You undeploy and the Thread keeps going, pinning ANOTHER set of class instances in PermGen. You redeploy and load a whole net set of copies... and eventually your PermGen fills up.

如果你的web应用程序不会关闭完全取消部署时-如果它离开正在运行的线程,例如-那么所有由该Web应用程序使用的类的实例将在PermGen的空间被固定。您重新部署,现在将所有这些 Class 实例的另一个完整副本加载到 PermGen 中。您取消部署并且线程继续运行,将另一组类实例固定在 PermGen 中。你重新部署并加载了一整套网络副本......最终你的永久代填满了。

You can sometimes fix this by:

您有时可以通过以下方式解决此问题:

  • Supplying command arguments to a recent Sun JVM to enable GC in PermGen and of classes. That is: -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
  • Using a different JVM that doesn't employ a fixed sized PermGen or that does GC on loaded classes
  • 向最近的 Sun JVM 提供命令参数以在 PermGen 和类中启用 GC。那是: -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
  • 使用不使用固定大小的 PermGen 或对加载的类执行 GC 的不同 JVM

But this will help onlyif your web app shuts down completely and cleanly, leaving no live references to any of the Class instances of any Class loaded by the Class loaders for that Web App.

但这只有在您的 Web 应用程序完全干净地关闭时才会有所帮助,不会留下对该 Web 应用程序的类加载器加载的任何类的任何类实例的实时引用。

Even this will not necessarily fix the problem, due to class loader leaks. (As well as too many interned strings in some cases.)

由于类加载器泄漏,即使这样也不一定能解决问题。(以及在某些情况下过多的实习字符串。)

Check out the following links for more (the two bolded ones have nice diagrams to illustrate part of the problem).

查看以下链接了解更多信息(两个粗体有很好的图表来说明问题的一部分)。

回答by OscarRyz

The problem in general terms is the security model of Java that actually attempts to prevent that a class that has already been loaded be loaded again.

一般而言,问题在于 Java 的安全模型实际上试图阻止已加载的类再次加载。

Of course Java since the beginning has supported dynamic class loading, what it is difficult is class re-loading.

当然Java从一开始就支持动态类加载,难的是类重新加载。

It was consider harmful ( and for a good reason ) that a running java application got injected with an new class with malicious code. For instance a java.lang.String cracked implementation comming from the internet , that instead of creating string, deletes some random file hile invoking the method length().

正在运行的 Java 应用程序被注入带有恶意代码的新类被认为是有害的(并且有充分的理由)。例如来自互联网的 java.lang.String 破解实现,它不是创建字符串,而是删除一些调用方法 length() 的随机文件 hile。

So, they way Java was conceived ( and I presume .NET CLR in consequence, because it was highly "inspired" in JVM's ) was to prevent an already loaded class to load again that same VM.

因此,他们构思 Java 的方式(因此我认为 .NET CLR,因为它在 JVM 中受到高度“启发”)是为了防止已加载的类再次加载同一个 VM。

They offered a mechanism to override this "feature". Classloaders, but again the rules for the class loaders was, they should ask permission to the "parent" classloader before attempting to load a new class, if the parent has already loaded the class, the new class is ignored.

他们提供了一种机制来覆盖这个“功能”。类加载器,但类加载器的规则是,在尝试加载新类之前,他们应该向“父”类加载器请求许可,如果父类已经加载了该类,则忽略新类。

For instance I have used classloaders that load a classes from LDAP or RDBMS

例如,我使用了从 LDAP 或 RDBMS 加载类的类加载器

The hot deploy becomes a necessity in the Java world when the application server became mainstream for Java EE ( and also create the need for micro containers like spring to avoid these kind of burden ) .

当应用服务器成为 Java EE 的主流时,热部署成为 Java 世界的必需品(并且还需要像 spring 这样的微容器来避免这些负担)。

Restarting the whole app server after every compile drives anyone crazy.

每次编译后重新启动整个应用程序服务器都会让任何人发疯。

So app server provider, offer this "custom" class loaders to help hot deployment, and using a configuration file, that behavior, SHOULD be disabled when set in production. But the tradeoff is you have to use tons of memory in development. So the good way to do this is restart every 3 - 4 deployments.

因此,应用服务器提供商提供此“自定义”类加载器以帮助热部署,并使用配置文件,在生产中设置时应禁用该行为。但代价是你必须在开发中使用大量内存。因此,最好的方法是每 3 到 4 次部署重新启动一次。

This doesn't happen with other languages that were designed from the beginning to load their classes.

对于从一开始就设计用于加载类的其他语言,则不会发生这种情况。

In Ruby for instance, you can even add methods to a running class, override a method at runtime or even add a single method to an unique specific object.

例如,在 Ruby 中,您甚至可以向正在运行的类添加方法,在运行时覆盖方法,甚至可以向唯一的特定对象添加单个方法。

The tradeoff in these kinds of environments is of course memory and speed.

在这些环境中的权衡当然是内存和速度。

I hope this helps.

我希望这有帮助。

EDIT

编辑

I've found this product some time ago that promises that reload is make as simple as possible. I didn't remember the link when I first wrote this answer, and I do.

前段时间我发现这个产品承诺重新加载尽可能简单。当我第一次写这个答案时,我不记得链接了,我记得。

It is JavaRebel from ZeroTurnaround

它是来自 ZeroTurnaround 的 JavaRebel

回答by Vladimir Dyuzhev

Sun JVM has PermGen space fixed, and eventually it's all consumed (yes, apparently due to a bug in classloader-related code) => OOM.

Sun JVM 已修复 PermGen 空间,最终它全部被消耗(是的,显然是由于与类加载器相关的代码中的错误)=> OOM。

If you can use another vendor's JVM (e.g. Weblogic one), it dynamically extends PermGen space, so you'll never get permgen-related OOM.

如果您可以使用其他供应商的 JVM(例如 Weblogic 的),它会动态扩展 PermGen 空间,因此您永远不会获得与 permgen 相关的 OOM。

回答by Ron

Which version of java are you using? There were bugs in early Sun 1.4.2, but it's been working for a long long time.
BTW, how will you break the news to your team lead? Are you the team lead?

你用的是哪个版本的java?Sun 1.4.2 早期存在错误,但它已经工作了很长时间。
顺便说一句,您将如何向您的团队负责人透露这个消息?你是领队吗?