GC 又叫垃圾回收器,释放垃圾占用空间。若想了解GC首先我们来看一下JVM的内存模型。
JVM 的内存主要分为如下几种类型的内存空间。
程序计数器:是一块较小的内存空间属于线程私有,它可以看做是程序运行时的灯塔它的工作就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基功能。
Java的栈:属于线程私有,它的生命周期与线程相同每个方法被执行的时候都会创建一个栈桢用于存储局部变量,操作栈,动态链接,方法出口等信息,每个方法被调用直至执行完成的过程,就对应着一个栈桢在虚拟机中入栈到出栈的过程。编译期可知的基本数据类型(字节炭)便存在这里。
本地方法栈:为虚拟机使用到的本地方法服务。
Java的堆:此内存区域的唯一目的就是存放对象实例可以处以物理上不连续的内存空间中,只要逻辑上连续即可。
方法区:用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
堆内存是所有线程共有的,可以分为两个部分:年轻代和老年代下图中的烫发。代表的是永久代,但是永久代并不属于堆内存的一部分。
GC 主要就是对堆内存进行垃圾清理。
年轻代可以分为:eden区,来自三个区域。为什么要分成三个区域呢?因为新生代采用的是复制算法,复制就意味着有一半的内存需要空闲等待。为了能让年轻代更为高效,就产生来自区。那么这两个的作用是什么呢?
当一个新的对象创建时,首先会去检查伊甸园区中还有没有足够的存储空间。如果有就会被直接放入伊甸园区,如果没有便会对伊甸园区进行GC。
1. 那么GC的流程是什么样子的呢?
首先会标记出eden中的垃圾对象,然后把非垃圾对象移到中,然后清空eden区。注意:从一个相互关系,有时候到会变成,有时候从变成到。但是能够确定的是他们之间总有一个是空闲的。(大家可以想下为什么年轻代的GC要采用复制算法)
那么是怎么判断出垃圾对象的呢?
判断一个对象是否是垃圾对象主要是通过这两种方式:每个对象的引用计数器是不是0,每个对象有没有根对象
2. 年轻代中的对象是什么时候进入到老年代中的呢?
a.当对象创建的时候,JVM会将其分配到伊甸区,但如果伊甸区内存不够这个新的对象进行存储,那就会直接把它分配老年代。
b.当这个对象在幸存区(来自)中的年龄达到了设定的值后变会被移到老年代中。
3. 老年代是如何进行GC的呢?
老年代GC是比较消耗机器性能的因为老年代中存放的是那些在程序中经历了好几次回收后,仍然还活着的特别大的对象老年代一般采用的是标记。 -清除或者标记-整理的算法。标记清除效率比较高,但是会产生大量的碎片,标记整理效率相对来说较低,但是不会产生连续的碎片块。
垃圾回收器(只针对fullGC,eden区GC大部分用复制算法)
1 串行收集器
缺点是:这种收集器是以单线程的方式收集,进行垃圾回收的时候其他线程也不能工作。
优点是:顺序收集,单线程资源好控制。
2 并行收集器
缺点是:进行垃圾回收的时候其他线程也不能工作。
优点是:。并行收集回收速度快资源同步复杂
3 并发收集器(CMS)
目前大部分系统采用的是这种收集器,该收集器暂停时间短,但是相当复杂.GC总时间长,暂停时间主要是发生在GCroot刚开始以及重新标记阶段。算法简记:1串行标记gc root直达对象.2并发标记可达对象3调整应用在运行时间产生,新建或变化的对象4并行回收。