这可能是因为我用错了关键词,没有太多的讨论或文章发现这个问题。
加载到JVM后,是否可以自动或手动释放一个Class
示例?
- 如果可以自动放行,这个程序什么时候执行?我们能期待一个时间点吗?
- 如果可以手工发布,怎么发布?有没有一些API?
- 如果它可以自动或手动释放,我们是否能够监控
Class
示例的终结,即使使用JVM之外的一些外部工具?
有些旧文章说,如果
- 没有对
Class
的任何示例/静态成员的引用 - 释放其
ClassLoader
示例
Class
将被发布。它是否适用于最新的JVM(例如,Oracle VM 17或GraalVM 17)?这是否意味着我们能够构建一些Class
以供即时使用,而不必担心内存泄漏?
class CustomClassLoader extends java.lang.ClassLoader
{
public CustomClassLoader()
{
super(CustomClassLoader.class.getClassLoader());
}
public Class<?> loadBytes(byte[] bytecode)
{
return defineClass(null, bytecode, 0, bytecode.length);
}
}
@SneakyThrows
Object testMethod()
{
// read a Class from bytecode by a local ClassLoader
byte[] bytecode = readSomeBytesFromSomewhere();
var cl = new CustomClassLoader();
Class<?> classTest = cl.loadBytes(bytecode);
// any random code
return classTest.getMethod("testMethodInClass").invoke(null);
}
public static void main(String... args)
{
for(int step = 0; step < 9999; step++)
testMethod();
}
对于上面的代码,我们是否可以认为每次testMethod
完成时,classTest
使用的任何资源都会被释放,因为它的ClassLoader
局部变量cl
从未被再次使用过?
1条答案
按热度按时间wi3ka0sx1#
对于上面的代码,我们是否可以认为每次testMethod完成时,classTest使用的任何资源都会被释放,因为它的ClassLoader局部变量cl从未被再次使用?
不,但我认为你在这里混淆了术语。特别是,任何资源,不。资源有一个非常具体的含义。它有必要被释放吗?不。再次,具体的含义。
所以让我试着具体一点:
释放?我想你是说收藏
如果由
cl.loadBytes
创建的对象是可垃圾回收的(从上面的代码可以看出,它是可垃圾回收的),和它的所有示例都是可垃圾回收的(在您的示例中是平凡的;您没有创建示例),并且ClassLoader对象是可收集的(同样,在您的代码中,它是可收集的),那么,也只有到那时,它才是可收集的。这是否意味着它会立即消失?不,这不是垃圾收集器的工作方式。如果收集器认为有必要这样做,它就会进行垃圾收集。如果收集器认为没有必要这样做,它就不会这样做。这对你来说无关紧要--垃圾仅仅存在是没有影响的。
关键是,JVM不会抛出OutOfMemoryError,因为有10,000个
Class
对象的副本填满了内存。“释放”是一个只在官方用语中用于表示资源的词。见下一节。
资源?我想您是指对象
资源是代表操作系统/架构级别概念的任何对象,* 因此必须手动关闭 * 该对象,释放该资源。
“resource”的一个例子是
new FileInputStream
。这是一个资源对象--你不需要依靠垃圾收集器来清理它,因为垃圾收集器可以自由地决定这个特定的对象在5天后是否需要清理。如果有足够的堆,为什么要这么做呢?这不是学术上的--这种情况真的会发生。因此,不要,永远不要,不使用try-with-resources
打开资源对象(或者将它们加载到一个本身为implements AutoClosable
的对象中,这样代码的用户就可以这样做)。这是唯一安全的方法。这就是所谓的“释放”。
你问的是关于资源和释放资源的问题,就像枪和奶奶一样:一点也不。
如果要使用资源,请使用try-with:
类加载器的恶作剧根本不会改变这一点。不使用try-with或手动推出try/finally循环,就不可能“自动释放”资源。