欢迎关注本人公众号

文章目录

  • 欢迎关注本人公众号
  • 概述
  • 代码实现

概述

之前我写了篇博客: java自定义类加载器实现类隔离 ,里面介绍了如何自定义类加载器实现了类隔离。

通常情况下,在JSP,OSGI及其他一些支持热替换的库,都是需要进行类的卸载回收的,否则类在替换后,老的类就没用了但是还在内存中,就会造成内存泄漏。

我们知道类的卸载需要满足以下三个条件:

  • 该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。
  • 加载该类的ClassLoader已经被GC。
  • 该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法。

所以在自定义类加载器时,就要注意这一点,如果你是希望其使用完成后就被卸载,那么就需要特别留意类加载器及类的作用域了。

代码实现

我这里还是在 java自定义类加载器实现类隔离 的基础上,对代码进行一些调整,使其可以在使用完成后可以被卸载。注意这里的代码只是学习使用的实例,如果用于生产环境还需要慎重。

在D盘的a,b两个目录下准备Hello.class 和 Dog.class 两个文件还是使用 java自定义类加载器实现类隔离 提到的方法来实现。

接下来对通过URLClassLoader实现的test0方法进行改造:

@Test
public void test0() throws Exception {test4();System.gc();TimeUnit.SECONDS.sleep(5);
}public void test4() throws Exception {System.out.println(this.getClass().getClassLoader());URLClassLoader diskLoader = new URLClassLoader(new URL[]{new URL("file:/D:/liubenlong/a/")});//最后面的斜杠需要添加URLClassLoader diskLoader1 = new URLClassLoader(new URL[]{new URL("file:/D:/liubenlong/b/")});//加载class文件Class clz = diskLoader.loadClass("Hello");Constructor constructor = clz.getConstructor(String.class);Object obj = constructor.newInstance("tom");/*** 类Hello引用了类Dog,类加载器会主动加载被引用的类。* 注意一般是我们使用 URLClassLoader 实现自定义的类加载器。如果使用classLoader,则需要重写findClass方法来实现类字节码的加载*/Method method = clz.getMethod("sayHello", null);//通过反射调用Test类的say方法method.invoke(obj, null);Class clz1 = diskLoader1.loadClass("Hello");Constructor constructor1 = clz1.getConstructor(String.class);Object obj1 = constructor1.newInstance("cat");Method method1 = clz1.getMethod("sayHello", null);//通过反射调用Test类的say方法method1.invoke(obj1, null);
}

这里System.gc();是为了主动触发GC进行类卸载。后面的sleep只是为了等待程序执行完成,输出结果。

然后需要添加启动参数-verbose:class来打印出类加载及类卸载的日志信息。

运行test0,输出

//省略部分日志
[0.482s][info][class,load] Hello source: file:/D:/liubenlong/a/
[0.483s][info][class,load] Dog source: file:/D:/liubenlong/a/
[0.484s][info][class,load] java.lang.invoke.StringConcatFactory source: jrt:/java.base
//省略部分日志
[0.508s][info][class,load] java.io.DataInputStream source: jrt:/java.base
a hi ...  java.net.URLClassLoader@3891771e
//省略部分日志
[0.549s][info][class,load] java.lang.invoke.LambdaForm$MH/0x0000000100101c40 source: java.lang.invoke.LambdaForm
a hello tom  java.net.URLClassLoader@3891771e
[0.552s][info][class,load] Hello source: file:/D:/liubenlong/b/
[0.556s][info][class,load] Dog source: file:/D:/liubenlong/b/
b hi ...  java.net.URLClassLoader@78ac1102
b hello cat  java.net.URLClassLoader@78ac1102
[0.560s][info][class,unload] unloading class Dog 0x0000000100102258
[0.560s][info][class,unload] unloading class Hello 0x0000000100102040
[0.560s][info][class,unload] unloading class Dog 0x00000001000a1a58
[0.560s][info][class,unload] unloading class Hello 0x00000001000a1840
[5.581s][info][class,load  ] java.lang.Shutdown source: jrt:/java.base
[5.581s][info][class,load  ] java.lang.Shutdown$Lock source: jrt:/java.baseProcess finished with exit code 0

日志中可以看出class load 和 unload 的信息,以及Hello和Dog类的类加载器。

注意,我这里时是加了一个test4方法来进行操作类及处理业务逻辑,test0调用test4方法并且调用System.gc();。如果System.gc();直接写道test4方法的末尾,是无法实现类的卸载的。读者可以自己实验。

原因是如果放在一起的话,都是同一个方法内,方法是虚拟机执行的最小单元,调用test4方法时会生成一个栈帧放到栈顶。test4方法的局部变量就会存在与栈帧中的局部变量表中,这里就有URLClassLoader类加载器及Hello/Dog类实例的引用,还包括一些动态链接,所以在GC时,由于栈帧中的内容是作为GC ROOT的,所以肯定不会被回收,故而不会进行类的卸载。
注意在实际开发中一定要保证类的实例, 该类的ClassLoader都被回收,并且没该类不可以被反射调用,才可以类卸载。

java自定义类加载器并观察类卸载过程相关推荐

  1. java 自定义类加载器_Java-JVM 自定义类加载器

    一.sun.misc.Launcher (ExtClassLoader 与 AppClassLoader 的创建) publicLauncher() { Launcher.ExtClassLoader ...

  2. Java 自定义类加载器教程

    文章目录 Java 自定义类加载器教程 loadClass findClass defineClass 函数调用过程 Java 自定义类加载器教程 除了在面试中遇到类的加载器的概率会高外,在实际的工作 ...

  3. java自定义类加载器

    import java.io.*;public class MyClassLoader extends ClassLoader{private String loaderName; //类加载器名称p ...

  4. java自定义类加载器与实现类加载器加密与解密

    创建自定义加载器的类 package com.tuogo.classlocad;import java.io.ByteArrayOutputStream; import java.io.FileInp ...

  5. java加载自己写的类_java 自定义类加载器从磁盘或网络加载类

    一.编写自定义类加载器类 package com.mybatis.entity; import java.io.ByteArrayOutputStream; import java.io.File; ...

  6. java中的类加载器有,Java自定义的类加载器,java自定义加载,在java中类加载器有以...

    Java自定义的类加载器,java自定义加载,在java中类加载器有以 在java中类加载器有以下几种java虚拟机自带的加载器 1)根类加载器(Bootstrap,c++实现)2)扩展类加载器(Ex ...

  7. 自定义类加载器_jvm超详细探索自定义类加载器(值得收藏)

    原创:鲁班学院子牙老师 微信公众号搜索启明南 如果你想看懂本篇文章,需要你对类加载器有一定的了解.如JVM自带的类加载器.双亲委派.自定义类加载器.类加载每个阶段做了什么--如果你对这些知识还有夹生的 ...

  8. java简单通讯录的实现02person类_Java自定义类加载器实现不同版本的类加载

    一 什么是类隔离技术 只要你 Java 代码写的足够多,就一定会出现这种情况:系统新引入了一个中间件的 jar 包,编译的时候一切正常,一运行就报错:java.lang.NoSuchMethodErr ...

  9. java import自定义类_Java实现的自定义类加载器示例

    本文实例讲述了Java实现的自定义类加载器.分享给大家供大家参考,具体如下: 一 点睛 1 ClassLoader类有如下两个关键方法: loadClass(String name, boolean ...

  10. 28 Java类的加载机制、什么是类的加载、类的生命周期、加载:查找并加载类的二进制数据、连接、初始化、类加载器、双亲委派模型、自定义类加载器

    28Java类的加载机制 28.1.什么是类的加载 28.2.类的生命周期 28.2.1.加载:查找并加载类的二进制数据 28.2.2.连接 28.2.3.初始化 28.3.类加载器 28.4.类的加 ...

最新文章

  1. OpenCV中的图像阈值处理算法
  2. NRF51822之动态广播使用
  3. Qt修炼手册7_图形:用户自定义QGraphicsItem
  4. 开头和结尾标记 在不同系统_写人作文的写作技巧。含思维导图、开头结尾写法及范文分析...
  5. 5.07—018—周二
  6. Arraylist理解(3)删除元素
  7. sftp日志linux,Linux下使用SFTP命令及FTP命令 (转)
  8. python循环小甲鱼教程_python之 小甲鱼教程 Easygui 篇
  9. Linux汇编调试器EDB
  10. DropDownList操作;ListBox操作;动态创建控件;Response.Write(欢迎学习ASP.NET''!);
  11. 产业园区数字孪生规划方案
  12. 2009国内免费网盘横向评测
  13. spss变量视图转数据视图_SPSS的数据视图和变量视图
  14. 参与微软本地化翻译——MLCP
  15. 信息系统项目管理师(2022年) —— 考试大纲
  16. 【性能】【内存】swap解读
  17. 阿里云ECS数据迁移到阿里云OSS
  18. vue实现自定义步骤条
  19. 简单记录下手机root 过程
  20. 光伏逆变simlink仿真(MPPT) 最大功率点追踪算法(MPPT)仿真模型,本设计基于扰动观察法(PO)最大功率点跟踪算法追踪光伏电池的发电曲线

热门文章

  1. Unity输入控制物体旋转和延迟缩放-课程作业
  2. Hexo博客使用LeanCloud统计页面访问次数
  3. git切换远程分支为develop
  4. 手把手带你在Java中用【数组】和【链表】实现栈
  5. activiti-邮件任务
  6. noip2011 公交观光
  7. 查询GPU时无进程运行,但是显存却被占用了
  8. win7/ubuntu18 双系统安装和卸载
  9. springMVC3.0后台验证信息不显示的原因初探
  10. python tensorflow 智能家居_用 TensorFlow 让你的机器人唱首原创给你听