文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
文章收录在网站:http://hardyfish.top/
内存分配策略
对象已死?
引用计数算法:
- Java虚拟机并不是通过引用计数算法来判断对象是否存活的
- 举个简单的例子:
- 对象objA和objB都有字段instance,赋值令
objA.instance = objB 及 objB.instance = objA
- 除此以外,这两个对象再无任何引用,实际上这两个对象已经不可能再被访问
- 但是他们因为互相引用着对方,导致他们的引用计数都不为领,引用计数算法也就无法回收它们
可达性分析算法:
- 可达性分析算法的基本思路就是通过一系列成为GC Roots的根对象作为起始节点集
- 从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为引用链(
Reference Chain
)- 如果某个对象到GC Roots间没有任何引用链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时
- 则证明此对象是不可能再被使用的
在Java技术体系里面,固定可作为GC Roots的对象包括以下几种:
在虚拟机栈(栈帧中的本地变量表)中引用的对象
- 譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等
在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量
在方法区中常量引用的对象,譬如字符串常量(String Table)里的引用
在本地方法栈JNI(即通常所说的Native方法)引用的对象
Java虚拟机内部的引用,如基本数据类型对应的Class对象
- 一些常驻的异常对象(比如NullPointerException、OutOfMemoryException)等,还有系统类加载器
所有被同步锁(sysnchronized关键字)持有的对象
反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
根据用户所选用的垃圾收集器以及当前回收的内存区域不同,还可以有其他对象临时性地加入
再谈引用
在JDK1.2版之后,Java对引用的概念进行了扩充
将引用分为强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)4种
这4种引用强度依次逐渐减弱:
- 强引用是最传统的引用的定义,是指在程序代码之中普遍存在的引用赋值
- 即类似于
Object obj = new Objec()
这种引用关系
- 永远不会被垃圾收集器回收
- 软引用是用来描述一些还有用、但非必须的对象
- 弱引用也是用来描述那些非必须对象,但是他的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止
- 虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系
- 一个对象是否有虚引用的存在,完全不会对其生存时间造成影响,也无法通过虚引用来取得一个对象实例
- 为一个对象设置虚引用关联的唯一目的只是为了能再这个对象被收集器回收时收到一个系统通知
生存还是死亡?
在可达性算法中被判定为不可达对象后,至少要经历两次标记过程对象才会真正死亡:
如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它会被第一次标记
- 随后进行一次筛选,筛选的条件是此对象是否有必要执行
finalize()
方法加入对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过
- 那么虚拟机将这两种情况都视为没有必要执行
如果这个对象判定为确有必要执行finalize()方法,那么该对象将会被放置在一个名为F-Queue的队列之中
- 并在稍后由一条虚拟机自动建立的、低调度优先级的Finalizer线程去执行它们的
finalize()
方法finalize()方法是对象逃脱死亡命运的最后一次机会
- 如果对象在finalize()中重新与引用链上的一个对象建立关联即可避免被回收
- 譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量。
回收方法区
方法区的垃圾收集主要回收两个部分内容:废弃的常量和不再使用的类型:
回收废弃常量:一个字符串java曾经进入常量池,但是当前系统有没有任何一个字符串对象的值是java
- 换句话说,已经没有任何字符串对象引用常量池中的
java
常量,且虚拟机中也没有其他地方引用这个字面量如果再这个时候发生内存回收就会被系统清理出常量池。常量池中其他类(接口)、方法、字段的符号引用也与此类似
判断一个类型是否属于不再被使用的类需要满足下面三个条件:
- 该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例
- 加载该类的类加载器已经被回收
- 该类对应的
java.lang.Class
对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法