对于java对象,什么是垃圾状态呢?就是不再被任何对象所引用.他就是垃圾.
在java中,GC的主要对象是堆空间和永久区。而我们更多讨论的是堆空间这部分。
堆的内存分配图
jdk8之前有永久代 jdk8之后被取消了,不再有永久代
GC的工作目的很明确:新生成的对象,都放在Eden中;当Eden充满时(小孩太多 了),GC将开始工作,首先停止应用程序的运行,开始收集垃圾。在堆中,找到已经无用的对象,并把这些对象占用的空间收回使其可以重新利用.大多数垃圾回收的 算法思路都是一致的:把所有对象组成一个集合,或可以理解为树状结构,从树根开始找,只要可以找到的都是活动对象,如果找不到,这个对象就是凋零的昨日黄 花,应该被回收了。
垃圾标记算法
我们如何标记一个对象是垃圾呢?主要有几种方法:引用计数法和可达性分析算法 这两种属于垃圾标记算法 并没有垃圾回收的功能
一.引用计数法的原理:对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,则对象A就不可能再被使用。
缺陷:引用和去引用伴随加法和减法,影响性能很难处理循环引用。所以主流java中并没有使用引用计数法。
二:可达性分析算法:通过判断对象的引用链,来判断对象是否可以被回收,他是整个程序中 对象所有的引用关系进行搜索记录,当GC根连接不到的对象,即标记为垃圾对象,如图灰色即为不可达对象.
什么对象可以称为根对象呢,主要有五种
虚拟机栈中引用的对象 方法区中常量引用的对象 方法区中类静态属性引用的对象 活跃线程引用的对象,本地方法栈jni(native方法)引用的对象(不熟悉)
垃圾回收算法
我们把对象标记为垃圾对象,接下来就是回收了
一.标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象,可达对象可理解为被引用的对象,因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。如图中,标记阶段先标记,清除阶段,清除未标记为引用的对象。
简单说就是标记阶段:从跟对象开始扫描,标记存活的对象,清除阶段,从堆内存进行线性扫描,清除垃圾对象
图1
标记清除算法的缺点:只清除了不引用的对象,会使那部分对象的空间不连续,造成空间碎片化.
二。复制算法:与标记-清除算法相比,复制算法是一种相对高效的回收方法,不适用于存活对象较多的场合 如老年代。复制算法一般使用在新生代,对新生代进行垃圾回收又叫做MinorGC(他和老年代不冲突)。
复制算法原理:将原有的内存空间分为两块,分为对象面和空闲面,每次只使用其中一块,对象创建在对象面,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的空闲面中,之后,清除对象块中的所有对象,交换两个内存的角色,完成垃圾回收.
图3
如上图3,复制算法执行后,先把存活对象复制到另一块区域,然后对之前区域进行一次清理,第一张图所画的A,B空间,把存活的对象由A复制到B,然后清理A区域,再把B区域存活对象复制到A,来回复制,每被复制一次,就会加一计数,当到达十五次(,默认应该是十五次,可以设置)之后,就进入了老年代,如下图4,还有一部分对象就是大对象,因为占得空间比较大,复制比较占空间,会直接进入老年代。
所以:少量对象存活,适合复制算法。大量对象存活,适合标记清理或者标记整理。
三.标记-压缩算法(也有的叫标记整理算法)适合用于存活对象较多的场合,如老年代一般使用这种算法,对老年代垃圾回收又叫MajorGC。它在标记-清除算法的基础上做了一些优化。和标记-清除算法基本思想一样,标记-压缩算法也首先需要从根节点开始,对所有可达对象做一次标记。但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端,就是移到一边。之后,清理边界外所有的空间。如图2
图二
标记压缩算法的优点:使用存活率较高的场景,避免内存不连续,不用设置两块内存,造成内存浪费
四:分代收集算法(比较主流的垃圾回收算法)
他是按照对象生命周期不同进行划分,划分到不同区域,进行不同的算法,是上面算法的一种组合算法
我们经常说哦full GC是其中的一种分类,还有一种是Minor GC
Minor 采用的就是复制算法
如上图在新生代中,新创建的对象一般都放在 Eden ,第一次复制 把里面存活的对象 放进S0 第二次复制,将Eden中&S0中对象,复制到S1,每次对象年龄加1.(S0个S1是新生代两块不同于Eden的区域)
什么时候对象从新生代进入老年代呢?主要有三种
1.默认是15岁之后,2新生代存不下,3超大对象 超过一定size的对象 这三种对象会进入老年代
老年代一般采用标记清理算法和标记整理算法 一般full GC就发生在老年代
full GC通常是堆垃圾回收 触发点主要有:
1.system.GC 2.老年代空间不足3MInor 去到老年代的对象大小 大于老年代的剩余空间 4.CMS GC出现异常
补充名词:
1.Stop-The-World:多半由于GC引起的,Java中一种全局暂停的现象,全局停顿,所有Java代码停止。native代码可以执行(但不能和JVM交互)。Jvm处于挂机状态,当然Dump,线程死锁检查,堆Dump,也是有可能引起全局暂停的现象,但多数还是GC引起,原因是GC的时候 ,只有这个线程执行,其他线程都是等待状态
2.可触及的对象:从根节点可以触及到这个对象。
3.不可触及的对象:在finalize()调用后,可能会进入不可触及状态,不可触及的对象不可能复活,可以回收。
4.可复活的对象:一旦所有引用被释放,就是可复活状态,因为在finalize()中可能复活该对象。
GC时为什么会有全局停顿?
类比在聚会时打扫房间,聚会时很乱,又有新的垃圾产生,房间永远打扫不干净,只有让大家停止活动了,才能将房间打扫干净。
JVM运行模式 server client 两者区别是:client启动快,运行慢.server启动慢 运行快 ,server启动是重量级的虚拟机,运行要快
注意事项:
1.当eden满了,触发young GC;
2.young GC做2件事:一,去掉一部分没用的object;二,把老的还被引用的object发到survior里面,等下几次GC以后,survivor再放到old里面。
3.当老年代满了,触发full GC。full GC很消耗内存,把old,young里面大部分垃圾回收掉。这个时候用户线程都会被block。
4.young generation比例越大,不一定最好。将young的大小设置为大于总堆大小的一半时会造成效率低下。如果设置得过小,又会因为young generation收集程序不得不频繁运行而造成瓶颈。
5.在sun 的文档说明中,对JVM堆的新域,是采用coping算法,该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。
看完算法,并不能学会如何优化jvm参数,感觉只是入门尝试
http://www.importnew.com/3146.html