classLoader加载的class的回收

2023-05-16

什么情况下,方法区中的类才会被回收?

1.该类所对应的所有实例对象都已经被回收了,Java堆中已经不存在该类的实例对象了。
2.加载该类的类加载器ClassLoader已经被回收了。
3.该类的Class对象没有任何引用。

关于第二句的理解,加载该类的类加载器ClassLoader已经被回收了,不单单是当前创建的ClassLoader被回收了,而是要真正加载这个classClassLoader回收了(即保存当前class的ProtectionDomain被回收了),当前类才会回收;这个和双亲委派机制有关!

demo如下

package com.kxf.test;

import java.lang.reflect.Method;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;

public class CustomClassLoader extends ClassLoader {
	// TestHelloWorld类名
	public static final String testClassName = "com.anbai.sec.classloader.TestHelloWorld";
	
	public static final String customLoaderStaticBean = "com.kxf.test.CustomLoaderStaticBean";
	
	// TestHelloWorld类字节码
	private static final byte[] testClassBytes = new byte[] { -54, -2, -70, -66, 0, 0, 0, 51, 0, 17, 10, 0, 4, 0, 13, 8, 0,
			14, 7, 0, 15, 7, 0, 16, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100,
			101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 5, 104, 101, 108,
			108, 111, 1, 0, 20, 40, 41, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103,
			59, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 19, 84, 101, 115, 116, 72, 101, 108, 108,
			111, 87, 111, 114, 108, 100, 46, 106, 97, 118, 97, 12, 0, 5, 0, 6, 1, 0, 12, 72, 101, 108, 108, 111, 32, 87,
			111, 114, 108, 100, 126, 1, 0, 40, 99, 111, 109, 47, 97, 110, 98, 97, 105, 47, 115, 101, 99, 47, 99, 108,
			97, 115, 115, 108, 111, 97, 100, 101, 114, 47, 84, 101, 115, 116, 72, 101, 108, 108, 111, 87, 111, 114, 108,
			100, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 3, 0, 4, 0,
			0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0,
			0, 1, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 7, 0, 1, 0, 9, 0, 10, 0, 1, 0, 7, 0, 0, 0, 27, 0, 1, 0, 1, 0, 0, 0,
			3, 18, 2, -80, 0, 0, 0, 1, 0, 8, 0, 0, 0, 6, 0, 1, 0, 0, 0, 10, 0, 1, 0, 11, 0, 0, 0, 2, 0, 12 };

	@Override
	public Class<?> findClass(String name) throws ClassNotFoundException {
		// 只处理TestHelloWorld类
		if (name.equals(testClassName)) {
			ProtectionDomain pd = new ProtectionDomain(new CodeSource(null, (Certificate[]) null),
                    null, this, null){
				@Override
				protected void finalize() throws Throwable {
					// TODO Auto-generated method stub
					super.finalize();
					System.out.println("CustomClassLoader ProtectionDomain finalize===");
				}
			};
			// 调用JVM的native方法定义TestHelloWorld类
			return defineClass(testClassName, testClassBytes, 0, testClassBytes.length, pd);
		}

		return super.findClass(name);
	}

	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		super.finalize();
		System.out.println("CustomClassLoader finalize===");
	}

	
}
package com.kxf.test;

import java.lang.ref.WeakReference;


public class ClassLoaderTest {
	static WeakReference<Class> reference = null;
	static WeakReference<Object> referenceObj = null;

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ClassLoader mClassLoader = new CustomClassLoader(){
			@Override
			protected void finalize() throws Throwable {
				// TODO Auto-generated method stub
				super.finalize();
				System.out.println("mClassLoader  finalize");
			}
		};
//		referenceObj = new WeakReference<Object>(new Object());
		
		try {
			Class<?> mClass = mClassLoader.loadClass("com.kxf.test.ClassLoaderBean");
			reference = new WeakReference<Class>(mClass);
			Object obj = mClass.newInstance();
			System.out.println("obj=="+obj);
			System.out.println("mClass getClassLoader=="+mClass.getClassLoader());
			System.out.println("mClass=="+mClass);
			
			Class testClass = mClassLoader.loadClass(CustomClassLoader.testClassName);
			System.out.println("testClass=="+testClass);
			System.out.println("testClass getClassLoader=="+testClass.getClassLoader());
			// 反射创建TestHelloWorld类,等价于 TestHelloWorld t = new TestHelloWorld();
			Object testInstance = testClass.newInstance();
			referenceObj = new WeakReference<Object>(testInstance);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		Thread thread = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.gc();
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println("reference=="+reference.get());
				System.out.println("referenceObj=="+referenceObj.get());
				
			}
		});
		thread.start();
	}

}

输出的日志如下:

ClassLoaderBean  static===
obj==com.kxf.test.ClassLoaderBean@1eb44e46
mClass getClassLoader==jdk.internal.loader.ClassLoaders$AppClassLoader@531d72ca
mClass==class com.kxf.test.ClassLoaderBean
testClass==class com.anbai.sec.classloader.TestHelloWorld
testClass getClassLoader==com.kxf.test.ClassLoaderTest$1@368102c8
CustomClassLoader ProtectionDomain finalize===
CustomClassLoader finalize===
mClassLoader  finalize
ClassLoaderBean  finalize===
reference==class com.kxf.test.ClassLoaderBean
referenceObj==null

由以上可以分析出,mClassLoader虽然被回收了,但是看的出来ClassLoaderBean并没有被回收,原因是ClassLoaderBean根本上是AppClassLoader加载的,具体的原因是ClassLoader的双亲委任模式;testClass会被回收,原因是生成的ProtectionDomain就在CustomClassLoader里面,即根本上加载testClass的ClassLoader就是mClassLoader本身。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

classLoader加载的class的回收 的相关文章

  • 将我的数据库类与项目中的其他类一起使用

    我有一个自己编写的自定义数据库类 还有一个用户类和一个站点类 MySQL 类有这样的方法 connect query clean fetch 用户等级 register login logout resetPass 站点类别 updateT
  • PHP - 使用大量参数和默认值初始化对象的最佳方法

    我正在设计一个类 它定义一个高度复杂的对象 其中包含大量 50 大部分可选参数 其中许多参数都有默认值 例如 type foo width 300 interactive false 我试图确定设置构造函数和实例 类变量的最佳方法 以便能够
  • Moq-ing 类或接口有什么区别?

    我一直在使用moq http code google com p moq 在我的单元测试中模拟对象 我在关于最小起订量的网站上看到它能够模拟类和接口 有一天 我与我的一位同事进行了讨论 他们表示没有理由模拟类 我应该只模拟接口 我对此并没有
  • 如何在 Windows 上使用 Pyreverse

    我想使用pyreverse 创建图表类 我下载它 当我使用这个命令时 pyreverse bat c PyreverseCommand a1 s1 f ALL o png test py 我收到错误 名称 点 无法识别 什么是 点 如何创建
  • 从另一个类访问和设置一个类中的变量

    我有一个 shopping cart aspx cs 文件 还有一个类文件 spcart cs 购物车 aspx cs public partial class Ui ShoppingCart System Web UI Page publ
  • 封装的闭包与类?

    我是 JS 来自 C etc 的新手 我突然想到闭包似乎是比类更简单 更方便的处理封装的方法 这段代码似乎给出了一种处理封装的简单方法 function addProperty o var value o get function retu
  • Java 从我创建的另一个类访问数组元素

    我正在使用 main 方法在类中创建一个数组 Word attempts new Word 26 Word 类中的字段是 private String attempts Word 类中的构造函数是 public Word int a att
  • java中类的命名约定 - 全部大写

    在 Java 中 当类全部大写时 如何命名它 例如 如果我想创建一个班级来选择某些人成为 VIP 我应该将类命名为 VIPSelector 还是 VipSelector Thanks 你的两个选择都有效 类的主要目标是让它们以大写字母开头
  • 从 python 中的类调用函数 - 不同的方式

    EDIT2 谢谢大家的帮助 编辑 添加 staticmethod后 它可以工作 但是我仍然想知道为什么我在这里遇到类型错误 我刚刚开始使用 OOPS 并且对它完全陌生 我有一个非常基本的问题 关于从类中调用函数的不同方式 我有一个 test
  • 使用上下文加载器加载资源失败并出现 NullPointerException

    我只是想知道为什么我无法使用 Felix OSGi 中的线程上下文加载器加载资源 我是否不应该接触上下文加载器 我是否做错了什么或者这是一个错误 我有一个超级简单的捆绑包 带有一个简单的激活器 public class Activator
  • 在正在运行的 JVM 中查找正在运行的实例

    我想知道是否可以获取给定类的正在运行的实例的句柄 触发此问题的特定问题是应用程序由于存在大量正在运行的线程而无法正常退出 是的 我知道您可以对 thead 进行守护进程 然后它们就不会阻止应用程序退出 但这确实让我想知道这是否可能 我能做的
  • ECMAScript 6 类中的 getter 和 setter 有何用途?

    我对 ECMAScript 6 类中 getter 和 setter 的意义感到困惑 什么目的 下面是我参考的一个例子 class Employee constructor name this name name doWork return
  • 从模板类创建对象时出错

    我一直在尝试找到一种方法 从 C 中的多元正态分布中采样随机向量 同时具有均值向量和协方差矩阵 就像 Matlab 的那样mvnrnd功能有效 我找到了实现此功能的类的相关代码这一页 http lost found wandering bl
  • JavaScript - 类根据条件扩展

    事情是这样的 我有一个名为 A 的主课 我希望这个班级能够扩展 B 级 class A extends B 但事实上 我希望 B 类在特定条件下扩展 C D 或 E class B extends B1 or class B extends
  • 类、模块、它们的特征类和方法查找

    我们来开公开课吧Module并向其中添加一个方法 class Module def foo puts phew end end 我可以通过这样做来调用这个方法 Class foo 这是可以理解的 因为类Class is Class 其超类是
  • 如何在 Angular 2 应用程序中从 TypeScript/JavaScript 中的字符串获取类?

    在我的应用程序中 我有这样的内容 user ts export class User 现在 我这样做 应用程序组件 ts callAnotherFunction User 如果我将类名作为字符串 即 我该如何做到这一点 User 如果可能的
  • 检查一个类是否是另一个类的子类

    我想在不创建实例的情况下检查一个类是否是另一个类的子类 我有一个类 它接收类名作为参数 作为验证过程的一部分 我想检查它是否属于特定的类系列 以防止安全问题等 有什么好的方法可以做到这一点吗 is subclass of http php
  • 用于多个窗口的 Tkinter 示例代码,为什么按钮无法正确加载?

    我正在编写一个程序 应该 按一下按钮即可打开一个窗口 按另一个按钮关闭新打开的窗口 我使用类 以便稍后可以将代码插入到更大的程序中 但是 我无法正确加载按钮 import tkinter as tk class Demo1 tk Frame
  • 动态创建类 - Python

    我需要动态创建一个类 为了更详细地讲 我需要动态创建 Django 的子类Form class 通过 动态 我打算根据用户提供的配置创建一个类 e g 我想要一个名为CommentForm这应该子类化Form class 该类应该有一个选定
  • 使类只能从特定类实例化

    假设我有 3 节课class1 class2 and class3 我怎样才能拥有它class1只能通过实例化class2 class1 object new class1 但不是 class3 或任何其他类 我认为它应该与修饰符一起使用

随机推荐