类的卸载
指类从内存中注销掉,注销完成后将不能再创建类的实例对象
当MySample
类加载,连接和初始化后,它的生命周期就开始了.
若代表MySample
类的Class对象不再被引用,即不可触及时,Class对象就会结束生命周期,MySample
类在方法区内的数据也会被卸载,从而结束MySample
类的生命周期
一个类何时结束生命周期,取决于代表他的Class对象何时结束生命周期
- 由JVM自带的类加载器所加载的类,在JVM生命周期类,始终不会被卸载
- JVM自带的类加载器包括根类加载器,扩展类类加载器,系统类加载器
- JVM本身会始终引用自带的类加载器,而这些类加载器则会始终引用他们所加载的类的Class对象—即这些Class对象始终是可触及的
- 由用户自定义的类加载器所加载的类是可以被卸载的
public class MyTest16 extends ClassLoader {
private String classLoaderName;
private final String fileExtension = ".class";
private String path;
public String getPath() {
return this.path;
}
public void setPath(String path) {
this.path = path;
}
public MyTest16(String classLoaderName) {
//将系统类加载器当做该类加载器的父加载器
super();
this.classLoaderName = classLoaderName;
}
public MyTest16(ClassLoader parent, String classLoaderName) {
//显示指定该类加载器的父加载器
super(parent);
this.classLoaderName = classLoaderName;
}
private byte[] loadClassData(String className) {
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
className = className.replaceAll("\\.", "/");
try {
String filePath = this.path + className + fileExtension;
is = new FileInputStream(new File(filePath));
int ch = 0;
while ((ch = is.read()) != -1) {
baos.write(ch);
}
data = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return data;
}
@Override
protected Class<?> findClass(String className) throws ClassNotFoundException {
System.out.println("findClass invoked : "+ className);
byte[] data = this.loadClassData(className);
return this.defineClass(className, data, 0, data.length);
}
@Override
public String toString() {
return "MyTest16{" +
"classLoaderName='" + classLoaderName + '\'' +
", fileExtension='" + fileExtension + '\'' +
'}';
}
public static void main(String[] args) throws Exception {
MyTest16 load1 = new MyTest16("load1");
// load1.setPath("/Users/lutingfeng/Documents/idea/jvm_learn/out/production/jvm_learn/main/jvm/classloader");
load1.setPath("/Users/lutingfeng/Desktop/");
Class<?> clazz = load1.loadClass("main.jvm.classloader.MyTest1");
System.out.println("clazz.hashCode="+clazz.hashCode());
Object obj = clazz.newInstance();
System.out.println(obj);
System.out.println("classLoad="+obj.getClass().getClassLoader());
load1 = null;
clazz = null;
obj = null;
System.gc();
load1 = new MyTest16("load1");
// load1.setPath("/Users/lutingfeng/Documents/idea/jvm_learn/out/production/jvm_learn/main/jvm/classloader");
load1.setPath("/Users/lutingfeng/Desktop/");
clazz = load1.loadClass("main.jvm.classloader.MyTest1");
System.out.println("clazz.hashCode="+clazz.hashCode());
obj = clazz.newInstance();
System.out.println(obj);
System.out.println("classLoad="+obj.getClass().getClassLoader());
}
}
在JVM参数中加上-XX:+TraceClassUnloading
并删除classPath
下的MyTest1.class
文件后执行结果:
findClass invoked : main.jvm.classloader.MyTest1
clazz.hashCode=2125039532
main.jvm.classloader.MyTest1@12a3a380
classLoad=MyTest16{classLoaderName=‘load1’, fileExtension=’.class’}
[Unloading class main.jvm.classloader.MyTest1 0x00000007c0060828]
findClass invoked : main.jvm.classloader.MyTest1
clazz.hashCode=1846274136
main.jvm.classloader.MyTest1@61bbe9ba
classLoad=MyTest16{classLoaderName=‘load1’, fileExtension=’.class’}
可见自定义ClassLoader—MyTest16
所加载的类MyTest1
被卸载