[置顶] 深入理解java虚拟机(四):对象存活判定算法和垃圾收集算法

时间:2022-01-24 10:15:05

深入理解java虚拟机(一):java内存区域(内存结构划分)
深入理解java虚拟机(二):java内存溢出实战
 
深入理解java虚拟机(三):String.intern()-字符串常量池
深入理解java虚拟机(四):对象存活判定算法和垃圾收集算法
深入理解java虚拟机(五):hotspot垃圾收集算法实现 
深入理解java虚拟机(六):java垃圾收集分析实战(内存分配与回收策略)
深入理解java虚拟机(七):java垃圾收集分析总结 

深入理解java虚拟机(八):java内存分析工具-MAT和OQL

 

 

程序计数器、虚拟机栈、本地方法栈3个区域随线程生,随线程而灭


栈中的栈帧随着方法的进入和退出而有条不紊的执行这出栈和入栈操作


每一个栈帧中分配多少内存基本上是在类结构确定下来是就已知的,因此这几个区域的内存分配和回收都具备确定性,在这几个区域内不需要过多考虑回收问题,因为方法结束或者线程结束时,内存就跟着回收了。


因此我们主要学习java堆和方法区的内存分配和回收。

一、对象存活判定算法

1、引用计数算法

原理:给对象添加一个引用计数器,每当有一个地方引用它时,计数器加1;引用失效时,计数器减1;计数器为0说明可被回收。
缺点:很难解决对象相互循环引用的问题(对象相互循环引用,但其实他们都已经没有用了)。

2、可达性分析算法

   java虚拟机采用的算法。
  原理:通过一些列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
  在java语言中,可作为GC Roots的对象包括下面几种:
       虚拟机栈(栈帧中的本地变量表)中引用的对象。
       方法区类静态属性引用的对象。
       方法区中常量引用的对象。
       本地方法栈中JNI引用的对象。

[置顶]        深入理解java虚拟机(四):对象存活判定算法和垃圾收集算法

二、垃圾收集算法

1、标记-清除算法(Mark-Sweep)

原理:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
缺点:容易产生内存碎片。

[置顶]        深入理解java虚拟机(四):对象存活判定算法和垃圾收集算法

2、复制算法(copying)

原理:先把内存分为大小相等的二个部分,每次只使用其中的一块,当这一块内存回收时,就把还存活的对象规则的复制到另一块内存中,以此循环。
  缺点:需要复制,效率降低、浪费空间。
  现代的虚拟机实现基本都采用这种算法来手机新生代。

[置顶]        深入理解java虚拟机(四):对象存活判定算法和垃圾收集算法

3、标记-整理算法(Mark-Compact)

原理:类似于标记-清除,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉端边界以外的内存。

[置顶]        深入理解java虚拟机(四):对象存活判定算法和垃圾收集算法

4、分代收集算法(Generational Collection)

原理:根据对象存活周期的不同将内存划分为几块。一般是java堆分为新生代和老年代,这样就可以根据各个年代的特点采用合适的收集算法。

三、回收方法区

  方法区的垃圾回收主要回收两部分:废弃常量和无用的类。


  回收废弃常量和java堆中的对象非常类似。当没有对象引用它时即可回收。


  回收无用的类则比较苛刻:
        该类所有的实例都已经被回收,即java堆中不存在该类的任何实例。
        加载该类的ClassLoader已经被回收。
        该类对应的java.lang.Class对象没有在任何地方被引用