单独的类加载器帮助垃圾收集

问题描述 投票:0回答:1

考虑一个由“设置代码”而不是运行时代码组成的 java 库。 设置代码可以包含许多定义带有选项表的菜单的类。 在应用程序运行时,很少会调用设置代码来执行更改配置属性等任务。

使用如下代码有优点吗?

public class Setup
{
    private static final class SetupClassLoader extends ClassLoader
    {   
        SetupClassLoader()
        {   
            super(Setup.class.getClassLoader());
        }   
    }   
    public static Setup getInstance() throws Exception
    {   
        SetupClassLoader scl = new SetupClassLoader();
        Class sc = scl.loadClass("com.example.Setup");
        return (Setup)sc.newInstance();
    }
    private ObjectWithLargeTablesOfData createObjectWithLargeTablesOfData()
    {
        ...

这个想法是,当不再引用Setup实例时,垃圾收集器可以更有效地释放它加载的所有内容,因为ClassLoader本身可以被收集。

如果不使用此方法,设置代码相关的类定义是否会留在内存中?

java performance garbage-collection classloader
1个回答
0
投票

首先要明白的是,不同的类加载器定义的运行时类是不同的类。 JVM,第 5.3 节。创建和加载:

创建后,类或接口不是单独由其名称决定,而是由一对确定:其二进制名称 (§4.2.1) 及其定义加载器。

但是即使没有规范,也可以认识到以下代码有一些奇怪的地方:

public static Setup getInstance() throws Exception
{   
    SetupClassLoader scl = new SetupClassLoader();
    Class sc = scl.loadClass("com.example.Setup");
    return (Setup)sc.newInstance();
}

此方法有两个对类的引用

Setup
,类型转换和返回类型。如果强制转换为
Setup
并将对象返回为
Setup
有效,则该对象的类型必须与此方法引用的
Setup
类型兼容,换句话说,它不能是自定义类加载器定义的类型当这个方法(可能还有调用者)引用它时,它可能会被垃圾收集。

这段代码没有失败的原因是你的类加载器根本没有尝试定义一个

Setup
类。它只是遵循标准委托模型

ClassLoader
类使用委托模型来搜索类和资源。
ClassLoader
的每个实例都有一个关联的父类加载器。当请求查找类或资源时,
ClassLoader
实例通常会将类或资源的搜索委托给其父类加载器,然后再尝试查找类或资源本身。

SetupClassLoader
的父加载器是
Setup.class.getClassLoader()
,所以显然在请求时找到该类没有问题,并且父加载器定义的这个类是调用代码引用的类,所以一切正常。除了这个类无法卸载并且给定调用代码使用该类的方式之外,没有办法在不破坏代码的情况下更改它。

换句话说,

SetupClassLoader
在这里没有任何作用,除了使代码复杂化并消耗一些内存之外。


真正动态加载的代码一定不能被静态代码引用,为了避免此类错误,动态类首先不应该被静态代码访问。但是,您将设置代码换成实现动态类加载的代码,而动态类加载必须保留在内存中。

因此,即使实施正确,它也不太可能带来好处。此外,请记住,类卸载是一个可选功能,因此在特定环境中甚至可能根本不会发生。

如果您确实有一个大型且复杂的用户界面,您可以考虑通过 XML 或 JSON 文件或类似的描述语言来描述菜单和 UI 布局等。然后,解析文件和构建 UI 的代码不依赖于 UI 大小。无论如何,要在 UI 中显示的文本应该放置在资源文件中,而不是设置代码中,例如允许翻译或修复错误,而无需重建应用程序。

© www.soinside.com 2019 - 2024. All rights reserved.