classLoader加载的class的回收

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

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本身。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值