这可能是因为我使用了错误的关键字,没有找到太多关于这个问题的讨论或文章。
加载到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();
}
上面的代码,我们可以考虑使用的任何资源classTest
将时常地公布testMethod
完成因为它ClassLoader
局部变量cl
永远不会再次使用吗?
对于上面的代码,我们是否可以认为classstest使用的任何资源将在每次testMethod完成时被释放,因为它的ClassLoader局部变量cl永远不会再次使用?
不,但我认为你在这里混淆了术语。具体来说,任何资源,没有。资源具有非常特定的含义。必须被释放吗? 不。再说一遍,具体的含义。
让我来具体点:
发布?我想你的意思是可收集的
如果cl.loadBytes
创建的对象是可垃圾收集的(从上面展示的代码来看,它是),和它的所有实例都是可收集的(在你的例子中微不足道;不创建实例),和ClassLoader对象是可收集的(同样,在你的代码中,它是可收集的),只有在那时,它才会是可收集的。
这是否意味着它会立即消失?不,垃圾收集器不是这样工作的。如果收集器认为有必要这样做,就会进行垃圾回收。如果收集器认为没有必要,它就不会这样做。这对你来说无关紧要——垃圾仅仅存在是没有影响的。
问题是,您的JVM不会抛出一个OutOfMemoryError,因为你有10000份Class
对象填充你的记忆。
"Released"这个词只在官方用语中用来指资源。
资源?我想你是指对象
资源是任何一个对象,该对象代表一个概念在OS/架构级别必须手动为了释放而关闭这个资源。
一个"资源"的例子是new FileInputStream
。这是一个对象,它是一个资源-你不依赖于垃圾收集器来清理它,因为垃圾收集器可以自由地决定这个特定的对象需要在5天后清理。如果有足够的堆,何必麻烦。这不是学术上的,这是真的。因此,不在没有使用try-with-resources
的情况下打开资源对象(或者将它们加载到一个本身具有implements AutoClosable
的对象中,以便代码的用户可以这样做)。这是唯一安全的方法。
这叫做"释放"。
你问的是关于资源和释放资源的问题,就像枪支和奶奶的问题一样:Not - at - all。
如果你想使用一个资源,你可以使用try-with:
// bad:
void foo() throws IOException {
var in = new FileInputStream(...);
// do stuff with 'in'
in.close();
}
// good:
void foo() throws IOException {
try (var in = new FileInputStream(...)) {
// do stuff with 'in
}
}
ClassLoader的诡计根本不会改变这一点。如果不使用try-with或手动执行try/finally循环,就不可能"自动释放"资源。