做者 某人Valar
如需转载请保留原文连接
部分图片来自百度,若有侵权请联系删除html
本文目录java
GC:垃圾回收(Garbage Collection),在计算机领域就是指当一个计算机上的动态存储器(内存空间)再也不须要时,就应该予以释放,以让出存储器,便于他用。这种存储器的资源管理,称为垃圾回收。算法
有一些语言是没有垃圾回收机制的,像
C
、C++
,若是须要释放无用变量内存空间就由本身来处理。bootstrap而其余的一些语言如
Java
、C#
都支持垃圾回收器,Java虚拟机(JVM)或.NET CLR发现内存资源紧张的时候,就会自动地去清理无用对象(没有被引用到的对象)所占用的内存空间。bash而咱们今天主要讲Java中的GC。网络
上面说到JVM
会自动清理无用的对象,那么咱们就有了疑问:oracle
JVM
清理的是哪一块的对象?JVM
又是如何清理的?这三个问题将分别对应接下来的3节一一解答。eclipse
咱们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程当中会把所管理的内存划分为若干个不一样的数据区域,这些区域都有各自的用途。 在《Java虚拟机规范(Java SE 8)》中描述了JVM运行时内存区域结构以下:jvm
以上是Java虚拟机规范,不一样的虚拟机实现可能会各有不一样,可是通常会遵照规范jsp
Java中经过可达性分析法来肯定某个对象是否是“垃圾”。
该方法的基本思想是经过一系列的“GC Roots”对象做为起点进行搜索,若是在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被断定为不可达的对象不必定就会成为可回收对象。被断定为不可达的对象要成为可回收对象必须至少经历两次标记过程,若是在这两次标记过程当中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。
注意其本质是经过找出全部活对象来把其他空间认定为“无用”,而不是找出全部死掉的对象并回收它们占用的空间.
以下图,当object五、六、7不存在到GC Roots的引用时,即不可到达GC Roots,则断定他们是不可达的。
对于哪些对象能够被当成GC Roots网上有不少种说法,有的不够权威、有的不够全面。 最终找到了一份eclipse的官方文档,里面有以下的介绍: Garbage Collection Roots (本身翻译了一下,若有不许确的地方,请指出)
A garbage collection root is an object that is accessible from outside the heap. The following reasons make an object a GC root:
1. System Class (被boostrap 或者系统类加载器加载的系统类)
Class loaded by bootstrap/system class loader. For example, everything from the rt.jar like java.util.* .
2. JNI Local( 一些用户定义jni 代码或者jvm的内部代码局部变量)
Local variable in native code, such as user defined JNI code or JVM internal code.
3. JNI Global( jni 代码中的全局变量)
Global variable in native code, such as user defined JNI code or JVM internal code.
5. Thread Block(被阻塞的线程引用的对象)
Object referred to from a currently active thread block.
6. Thread (正在运行的线程)
A started, but not stopped, thread.
7. Busy Monitor(正在等待的线程)
Everything that has called wait() or notify() or that is synchronized.
For example, by calling synchronized(Object) or by entering a synchronized method.
Static method means class, non-static method means object.
8. Java Local(仍然在线程的栈中的方法的传入参数或方法内部建立的对象)
Local variable.
For example, input parameters or locally created objects of methods that are still in the stack of a thread.
9.Native Stack(本地方法栈中输入或输出参数,例如,用于文件/网络I/O的方法或反射的参数。)
In or out parameters in native code, such as user defined JNI code or JVM internal code.
This is often the case as many methods have native parts and the objects handled as method parameters become GC roots.
For example, parameters used for file/network I/O methods or reflection.
10.Finalizable(在回收队列中的对象)
An object which is in a queue awaiting its finalizer to be run.
11. Unfinalized(覆盖了finalize方法可是尚未被放入回收队列中的对象)
An object which has a finalize method, but has not been finalized and is not yet on the finalizer queue.
12.Unreachable(一个从任何其余根没法访问的对象,但由Memory Analyzer Tool 标记为根,以便该对象能够包含在分析中)
An object which is unreachable from any other root,
but has been marked as a root by MAT to retain objects which otherwise would not be included in the analysis.
13. Java Stack Frame
A Java stack frame, holding local variables.
Only generated when the dump is parsed with the preference set to treat Java stack frames as objects.
14. Unknown
An object of unknown root type. Some dumps, such as IBM Portable Heap Dump files, do not have root information.
For these dumps the MAT parser marks objects
which are have no inbound references or are unreachable from any other root as roots of this type.
This ensures that MAT retains all the objects in the dump.
复制代码
简单总结下就是:
这是最基础的垃圾回收算法,之因此说它是最基础的是由于它最容易实现,思想也是最简单的。标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出全部须要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。具体过程以下图所示:
为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另一块上面,而后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。具体过程以下图所示:
该算法标记阶段和Mark-Sweep同样,可是在完成标记以后,它不是直接清理可回收对象,而是将存活对象都向一端移动,而后清理掉端边界之外的内存。具体过程以下图所示:
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不一样的区域。 通常状况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),在HotSpot中,设计者将方法区归入也归入了GC分代收集,并为其起了一个名字,永久代(PerGen space)。
标记-整理(Mark-Compact)
、标记-清除(Mark-Sweep)
算法。取复制(Copying)
算法。由于新生代中每次垃圾回收都要回收大部分对象,也就是说须要复制的操做次数较少,可是实际中并非按照1:1的比例来划分新生代的空间的,通常来讲是将新生代划分为一块较大的Eden空间(伊甸园,亚当和夏娃偷吃禁果生娃娃的地方,用来表示内存首次分配的区域,再贴切不过)和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另外一块Survivor空间中,而后清理掉Eden和刚才使用过的Survivor空间。通常来讲分配比例为eden 80%、survivor1 10%、survivor2 10%。
在方法区进行垃圾回收通常”性价比”较低, 由于在方法区主要回收两部份内容: 废弃常量和无用的类。 回收废弃常量与回收其余年代中的对象相似, 但要判断一个类是否无用须要如下条件:
- 该类全部的实例都已经被回收, Java堆中不存在该类的
任何实例
;- 该类对应的
Class对象
没有在任何地方被引用(也就是在任何地方都没法经过反射访问该类的方法);- 加载该类的
ClassLoader
已经被回收。但即便知足以上条件也未必必定会回收, Hotspot VM还提供了
-Xnoclassgc
参数控制(关闭CLASS的垃圾回收功能).
附:HotSpot虚拟机在1.8以后已经取消了永久代,改成元空间,类的元信息被存储在元空间中,元空间这里不过多介绍,有兴趣的同窗能够本身了解下。
到此关于Java GC的基本概念、JVM的内存结构、GC回收基本机制都已经介绍的差很少了。有疑问或者发现文章中有错误的能够在下方留言交流。像Java垃圾收集器、元空间这里并无详细的说明,以后有时间的话会单独拿出来聊聊。