【转】JVM类装载机制的解析,热更新的探讨(二)
同样,一个Class对象必须知道自己的超类、超级接口。因此,Class对象会引用自己的超类和超级接口的Class对象。这种引用一定是实例引用。(实际上,超类、超级接口的引用也存储在常量池中,但为了区分依赖类的引用,将它特殊表述一下。)
因此,我暂且得到两条结论。
结论一:持有一个Class对象的引用,则任何该Class对象直接或间接依赖的所有类(如果被加载了),都不可能被卸载。同样,只要有一个类直接或间接依赖某个类,则该类不可能被卸载。
结论二:持有一个Class对象的引用,则该类的所有超类、超接口都不能被卸载。同样,如果任何一个类(或接口)存在一个没有被卸载的子类(或实现类、子接口),则该类(接口)不可能被卸载。
由此可见,对于一个软件而言,其所有class文件可以看做一个从包含main方法的根节点出发,在一张依赖图中搜索所有可达节点,所有可达节点构成的集合。而这个集合中的绝大部分类,要么全部保留在内存中,要么全部卸载。
对于一个模块而言,如果该模块之间的类彼此都存在依赖,则该模块必须整个地被卸载。因此,如果一个应用程序想要利用一个模块卸载另外一个模块。必要条件就是,执行卸载操作的模块必须零依赖被卸载的模块。
零依赖的含义就是,被依赖的模块是完全透明的,是不可见的。
根据上面的结论,卸载必须是以模块为单位。因此,所谓卸载一个强耦合的类是完全不可能的。因此,我可以放弃说“卸载类”,而应该说“卸载模块”。
那么,卸载一个模块的充分条件是什么呢?
回到前面的那张引用关系图,让我们来看看那些其他要素可能引用Class对象。
对于任何一个Java对象而言,它都一定是某个类的实例,因此,它能直接或间接的引用到该类的Class对象。这一推论的理由有三,其一,JVM在将对象进行向下转型、instanceof判定的时候,一定要知道对象的类型,倘若对象无法引用到类的Class对象,这个过程何以进行呢?其二,子类可重写父类的方法,运行时的多态令虚拟机能正确调用到对象方法(防止子类调用到父类被覆盖的方法),如果不知对象类型,何以实现?其三,Object类有一个native方法getClass()可以直接获取对象的类Class对象。
类加载器在加载了一个类之后,当第二次接受到该类的类名之后,加载器会直接返回该类的对象,而不是重复加载该类。虚拟机绝不允许同一个命名空间中的一个类被加载了两次,因此类加载器必须缓存所有它加载的类的Class对象,以供返回。
此外,ClassLoader也好,Class对象也好,这些本身能被变量所引用。如果某些可达的变量(局部变量、成员变量、静态变量)引用了它们,自然也会让整个模块变得可达而无法被卸载。
此外,某些特殊的类加载器永远是可达的,它们是Bootstrap、Extendsion、System。因此,我可以得出一条结论。
结论三:Java的标准类库一旦加载,永远不能卸载。
结论四:CLASS_PATH中的类(系统加载器加载的类),一旦加载,永远不能被卸载。
因此,一个模块中的所有类必须使用同一个ClassLoader实例加载。而且这个ClassLoader实例不能是Extendsion和System。这个ClassLoader实例的控制权必须掌握在操作卸载的模块那里。随时释放该实例的引用,使ClassLoader变得不可达。
此外,该模块任意类的实例都必须是不可达的,存在任何一个可达的该模块类的实例,模块都无法释放。
至此,我得到了卸载模块的充分条件:模块的全部类由一个可控的ClassLoader加载;释放该模块的定义类加载器引用;释放该模块所有类的实例引用;释放该模块的Class对象引用。
还有,模块的定义类加载器、类实例、Class对象,这些东西,只要没有引用掌握在其他模块那里,也没有掌握在栈内存中,就一定可以卸载模块。特别的,模块自己引用了这些东西,尤其是模块的静态变量引用了这些东西,那是完全不影响卸载的。
有一种观点认为,垃圾回收判断的根节点包括所有类的静态变量,这是错误的。实际上如果一个模块变得不可达了,它的所有的类的静态变量也会变得不可达,并会被回收释放。
转自:
http://taozeyu.com/software/2014/03/15/jvm-class-loader-2.html
【转】JVM类装载机制的解析,热更新的探讨(二)的更多相关文章
- 【转】JVM类装载机制的解析,热更新的探讨
引言 如有错误,请批评指正. Java是一种动态连接的语言.所谓动态连接,大概可以这么解释. 首先,Java可以大概想象成是编译解释执行的.对于一个*.java的文件,通过javac将会编译成一个*. ...
- 深入研究Java类装载机制
目录 1.为什么要研究java类装在机制? 2.了解类装载机制,对于我们在项目开发中有什么作用? 3.装载实现细节. 4.总结 一.为什么药研究Java类装载机制 java类加载机制,便于我们使用自定 ...
- JVM的类加载机制全面解析
什么是类加载机制 JVM把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制. 如果你对Class文件的结 ...
- 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用FairyGUI (二)
上次讲解了FairyGUI的最简单的热更新办法,并对其中一个Demo进行了修改并做成了热更新的方式. 这次我们来一个更加复杂一些的情况:Emoji. FairyGUI的 Example 04 - ...
- Unity热更新学习(二) —— ToLua c#与lua的相互调用
tolua 下载地址:http://www.ulua.org/index.html c#调用lua的方法,tolua的官方例子提供了很多种.我初步学了一种在做项目使用的方法.通过DoFile方法执行l ...
- Unity3D热更新全书-脚本(二) 两级分化
上篇明确了我们探讨的脚本是什么:是写在文本文件里面的代码,可以作为资源加载,取得字符串再执行. 可是为什么世界上会有那么多的脚本?而其使用方法完全看起来不一样呢?这是因为每种脚本都有自己的定位,在不同 ...
- Unity手游之路<十二>手游资源热更新策略探讨
http://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游资源的增量更新策略. ...
- [unity3d]手游资源热更新策略探讨
原地址:http://blog.csdn.net/dingxiaowei2013/article/details/20079683 我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游 ...
- [转]Unity手游之路<十二>手游资源热更新策略探讨
最近梳理了下游戏流程.恩,本来想写下,但是,还是看前辈的吧 版权声明: https://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何 ...
随机推荐
- UCOSII软件定时器
API函数 //创建 OS_TMR *OSTmrCreate (INT32U dly, INT32U period, INT8U opt, OS_TMR_CALLBACK callback, void ...
- iPhone 移植到 iPad:
来源:http://www.wapera.cn/ipadkaifa/71354.html iPhone移植到iPad: 方法一修改设备目标设置(普通模式:一套代码及XIB界面文件,代码分if和else ...
- TCP_Wrappers基础知识介绍
1. TCP_Wrappers基础知识介绍 TCP_Wrappers是在 Solaris, HP_UX以及 Linux中广泛流行的免费软件.它被设计为一个介于外来服务请求和系统服务回应的中间处理软件. ...
- windows nginx
nginx.exe -s stop stop是快速停止nginx,可能并不保存相关信息: nginx.exe -s quit quit是完整有序的停止nginx,并保存相关信息. nginx.exe ...
- ASP.NET Core 2.2 项目升级至 3.0 备忘录
将 ASP.NET Core 2.2 迁移至 ASP.NET Core 3.0 需要注意的地方记录在这篇随笔中. TargetFramework 改为 netcoreapp3.0 <Target ...
- 关于MQ的几件小事:消息队列的用途、优缺点、技术选型
原文:https://www.cnblogs.com/jack1995/p/10908789.html 1.为什么使用消息队列? (1)解耦:可以在多个系统之间进行解耦,将原本通过网络之间的调用的方式 ...
- vscode——设置自动保存
前言 懒就一个字 步骤 打开设置第一项就是,选择焦点改变自动保存即可
- docker 进程 转载:
今天我们会分析Docker中进程管理的一些细节,并介绍一些常见问题的解决方法和注意事项. 容器的PID namespace(名空间) 在Docker中,进程管理的基础就是Linux内核中的PID名空间 ...
- react 学习记录
1. 脚手架搭建项目 create-react-app https://www.jianshu.com/p/d196761c8332 2. UI框架 https://ant.design/docs ...
- celery retry发送的队列
celery retry时,将发送到原有的队列,并在任务中加入执行的时间,以及当前重试的次数. worker立刻读取该任务,同时记录一条[任务]到 unacked中,表示该任务在worker中还未执行 ...