`
goodscript
  • 浏览: 71952 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

从一个小例子来看动态卸载class

 
阅读更多
先看一个实例

使用URLClassLoader每隔3秒钟重复加载A类的class
  假如在这3秒钟内我们把class修改了
  将会得到什么样的结果:

  -------------------------------------
package jvm;

import java.net.URL;
import java.net.URLClassLoader;

public class Test {

	public static void main(String[] args) {

		while (true) {
			try {
				ClassLoader parentLoader = Test.class.getClassLoader();
				URLClassLoader loader1 = new URLClassLoader(new URL[] { null }, parentLoader);
				Class<?> cls1 = loader1.loadClass("jvm.A");
				A excel = (A) cls1.newInstance();
				excel.print();
				Thread.sleep(1000 * 3);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

package jvm;

public class A {
	private String className = "class A";//修改成员变量 class A
	static {
		System.out.println(" static  block initialization ");//修改静态成员变量的打印内容 static  block initialization  change
	}

	//	private String addField = "field 1";//运行时添加一个成员变量
	public void print() {
		System.out.println("hello ");//修改方法内的打印内容hello change
		System.out.println("------------------" + className);
		System.out.println("the end");
	}
	//运行时添加一个成员方法
	//	public void print2() {
	//		System.out.println("hello ");//修改方法内的打印内容hello change
	//		System.out.println("------------------" + className);
	//		System.out.println("the end");
	//	}
}


以debug的方式运行、按照下面的修改后运行得到的结果
--------------------------------
  1、修改成员变量的值------------动态打印修改后的值
  2、修改成员方法的打印内容-------动态打印修改后的值
  3、添加成员变量-----------提示警告
  4、添加成员方法-----------提示警告
  5、删除成员变量-----------提示警告
  6、删除成员方法-----------提示警告

根据以上运行结果
class类加载到虚拟机之后无法添加或者删除成员变量及成员方法
但是可以修改成员变量的值或者修改成员方法中的内容




从另一个角度分析     
                
从JVM结构的角度分析,class的结构信息存放在java的方法区内(method Area).包括常量池、字段描述、方法描述等等
常量池:用于存放编译期已可知的常量,这部分内容将在类加载后进入方法区(永久代)存放。但是Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池,运行期间也可将新内容放入常量池。
字段信息和方法描述:在编译时期就已经载入到方法区中。运行时无法对该部分的内容进行修改
方法区可以选择不实现垃圾收集、开源的JVM默认是不实现垃圾收集。
方法区是否需要实现垃圾收集其实是一个很难取舍的问题:
假如对方法区的内存进行垃圾收集、可以想象下次再实例化对象需要重新加载class信息无疑是加重了实例化对象的负担
假如不对方法区的内存进行垃圾收集、则无法动态修改一个class的结构;只能修改一些成员变量、成员方法的内容
相对一些热部署的应用将无法实现
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics