在java中卸载类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/148681/
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
Unloading classes in java?
提问by el_eduardo
I have a custom class loader so that a desktop application can dynamically start loading classes from an AppServer I need to talk to. We did this since the amount of jars that are required to do this are ridiculous (if we wanted to ship them). We also have version problems if we don't load the classes dynamically at run time from the AppServer library.
我有一个自定义类加载器,以便桌面应用程序可以从我需要与之交谈的 AppServer 动态开始加载类。我们这样做是因为这样做所需的罐子数量是荒谬的(如果我们想运送它们)。如果我们不在运行时从 AppServer 库动态加载类,我们也会遇到版本问题。
Now, I just hit a problem where I need to talk to two different AppServers and found that depending on whose classes I load first I might break badly... Is there any way to force the unloading of the class without actually killing the JVM?
现在,我遇到了一个问题,我需要与两个不同的 AppServer 对话,并发现根据我首先加载的类,我可能会严重崩溃......有没有办法强制卸载类而不实际杀死 JVM?
Hope this makes sense
希望这是有道理的
采纳答案by Mario Ortegón
The only way that a Class can be unloaded is if the Classloader used is garbage collected. This means, references to every single class and to the classloader itself need to go the way of the dodo.
卸载类的唯一方法是使用的类加载器是否被垃圾收集。这意味着,对每个类和类加载器本身的引用都需要遵循 dodo 的方式。
One possible solution to your problem is to have a Classloader for every jar file, and a Classloader for each of the AppServers that delegates the actual loading of classes to specific Jar classloaders. That way, you can point to different versions of the jar file for every App server.
您的问题的一种可能解决方案是为每个 jar 文件使用一个类加载器,并为每个 AppServer 使用一个类加载器,将类的实际加载委托给特定的 Jar 类加载器。这样,您可以为每个应用服务器指向不同版本的 jar 文件。
This is not trivial, though. The OSGi platform strives to do just this, as each bundle has a different classloader and dependencies are resolved by the platform. Maybe a good solution would be to take a look at it.
不过,这并非微不足道。OSGi 平台努力做到这一点,因为每个包都有不同的类加载器,并且依赖关系由平台解决。也许一个好的解决方案是看一看。
If you don't want to use OSGI, one possible implementation could be to use one instance of JarClassloaderclass for every JAR file.
如果您不想使用 OSGI,一种可能的实现可能是为每个 JAR 文件使用JarClassloader类的一个实例。
And create a new, MultiClassloader class that extends Classloader. This class internally would have an array (or List) of JarClassloaders, and in the defineClass() method would iterate through all the internal classloaders until a definition can be found, or a NoClassDefFoundException is thrown. A couple of accessor methods can be provided to add new JarClassloaders to the class. There is several possible implementations on the net for a MultiClassLoader, so you might not even need to write your own.
并创建一个新的 MultiClassloader 类来扩展 Classloader。这个类在内部会有一个 JarClassloader 的数组(或列表),并且在 defineClass() 方法中将遍历所有内部类加载器,直到可以找到定义,或者抛出 NoClassDefFoundException。可以提供几个访问器方法来向类添加新的 JarClassloader。MultiClassLoader 网络上有几种可能的实现,因此您甚至可能不需要编写自己的实现。
If you instanciate a MultiClassloader for every connection to the server, in principle it is possible that every server uses a different version of the same class.
如果您为每个到服务器的连接实例化一个 MultiClassloader,原则上每个服务器都可能使用同一类的不同版本。
I've used the MultiClassloader idea in a project, where classes that contained user-defined scripts had to be loaded and unloaded from memory and it worked quite well.
我在一个项目中使用了 MultiClassloader 的想法,其中包含用户定义的脚本的类必须从内存中加载和卸载,并且效果很好。
回答by Jason Cohen
You can unload a ClassLoader but you cannot unload specific classes. More specifically you cannot unload classes created in a ClassLoader that's not under your control.
您可以卸载 ClassLoader,但不能卸载特定类。更具体地说,您不能卸载在不受您控制的 ClassLoader 中创建的类。
If possible, I suggest using your own ClassLoader so you can unload.
如果可能,我建议使用您自己的 ClassLoader,以便您可以卸载。
回答by Steve g
Classloaders can be a tricky problem. You can especially run into problems if you're using multiple classloaders and don't have their interactions clearly and rigorously defined. I think in order to actually be able to unload a class youlre going go have to remove all references to any classes(and their instances) you're trying to unload.
类加载器可能是一个棘手的问题。如果您使用多个类加载器并且没有明确和严格地定义它们的交互,则尤其会遇到问题。我认为为了真正能够卸载您将要卸载的类,必须删除对您尝试卸载的任何类(及其实例)的所有引用。
Most people needing to do this type of thing end up using OSGi. OSGi is really powerful and surprisingly lightweight and easy to use,
大多数需要做这种事情的人最终都会使用OSGi。OSGi 非常强大,而且非常轻巧且易于使用,
回答by Georgi
Yes there are ways to load classes and to "unload" them later on. The trick is to implement your own classloader which resides between high level class loader (the System class loader) and the class loaders of the app server(s), and to hope that the app server's class loaders do delegate the classloading to the upper loaders.
是的,有一些方法可以加载类并稍后“卸载”它们。诀窍是实现您自己的类加载器,它位于高级类加载器(系统类加载器)和应用服务器的类加载器之间,并希望应用服务器的类加载器确实将类加载委托给上层加载器.
A class is defined by its package, its name, and the class loader it originally loaded. Program a "proxy" classloader which is the first that is loaded when starting the JVM. Workflow:
一个类由它的包、它的名称和它最初加载的类加载器定义。编写一个“代理”类加载器,它是启动 JVM 时加载的第一个类加载器。工作流程:
- The program starts and the real "main"-class is loaded by this proxy classloader.
- Every class that then is normally loaded (i.e. not through another classloader implementation which could break the hierarchy) will be delegated to this class loader.
- The proxy classloader delegates
java.x
andsun.x
to the system classloader (these must notbe loaded through any other classloader than the system classloader). - For every class that is replaceable, instantiate a classloader (which really loads the class and does not delegate it to the parent classloader) and load it through this.
- Store the package/name of the classes as keys and the classloader as values in a data structure (i.e. Hashmap).
- Every time the proxy classloader gets a request for a class that was loaded before, it returns the class from the class loader stored before.
- It should be enough to locate the byte array of a class by your class loader (or to "delete" the key/value pair from your data structure) and reload the class in case you want to change it.
- 程序启动,真正的“主”类由这个代理类加载器加载。
- 然后正常加载的每个类(即不通过可能破坏层次结构的另一个类加载器实现)将被委托给这个类加载器。
- 代理类加载器的代表
java.x
,并sun.x
在系统类加载器(这些不得通过任何其他的类加载器不是系统类加载器加载)。 - 对于每个可替换的类,实例化一个类加载器(它真正加载类而不将它委托给父类加载器)并通过它加载它。
- 将类的包/名称存储为键,并将类加载器存储为数据结构(即 Hashmap)中的值。
- 每次代理类加载器收到对之前加载的类的请求时,它都会从之前存储的类加载器中返回该类。
- 通过类加载器定位类的字节数组(或从数据结构中“删除”键/值对)并重新加载类,以防万一你想改变它应该就足够了。
Done right there should not come a ClassCastExceptionor LinkageErroretc.
做对了不应该出现ClassCastException或LinkageError等。
For more informations about class loader hierarchies (yes, that's exactly what you are implementing here ;- ) look at "Server-Based Java Programming" by Ted Neward- that book helped me implementing something very similar to what you want.
有关类加载器层次结构的更多信息(是的,这正是您在此处实现的内容;-)查看Ted Neward 的“基于服务器的 Java 编程”——这本书帮助我实现了与您想要的非常相似的东西。
回答by Tom Hawtin - tackline
Classes have an implicit strong reference to their ClassLoader instance, and vice versa. They are garbage collected as with Java objects. Without hitting the tools interface or similar, you can't remove individual classes.
类具有对其 ClassLoader 实例的隐式强引用,反之亦然。它们与 Java 对象一样被垃圾收集。如果不点击工具界面或类似界面,就无法删除单个类。
As ever you can get memory leaks. Any strong reference to one of your classes or class loader will leak the whole thing. This occurs with the Sun implementations of ThreadLocal, java.sql.DriverManager and java.beans, for instance.
与以往一样,您可能会遇到内存泄漏。对您的类或类加载器之一的任何强引用都会泄露整个内容。例如,在 ThreadLocal、java.sql.DriverManager 和 java.beans 的 Sun 实现中就会发生这种情况。
回答by Kamran
I wrote a custom classloader, from which it is possible to unload individual classes without GCing the classloader. Jar Class Loader
我编写了一个自定义类加载器,可以从中卸载单个类,而无需对类加载器进行 GC。Jar 类加载器