Java虚拟机垃圾回收

来源:互联网 发布:淘宝手机端网址转化 编辑:程序博客网 时间:2024/05/17 08:42

http://www.cnblogs.com/ityouknow/p/5610232.html
http://blog.csdn.net/u014381710/article/details/48554465

Java虚拟机调优主要两方面:无监控不调优! 1. 堆内存参数 2. 垃圾回收器

JVM内存结构

这里写图片描述
[方法区][1]是java虚拟机规范去中定义的一种概念上的区域,具有什么功能,但并没有规定这个区域到底应该位于何处,因此对于实现者来说,如何来实际方法区是有着很大自由度的。
永生代是hotspot中的一个概念,其他jvm实现未必有,例如jrockit就没这东西。java8之前,hotspot使用在内存中划分出一块区域来存储类的元信息、类变量以及内部字符串(interned string)等内容,称之为永生代,把它作为方法区来使用。
[JEP122][2]提议取消永生(久)代,方法区(永久区)作为概念上的区域仍然存在。原先永生代中类的元信息会被放入本地内存(元数据区,metaspace),将永久代的一些杂项,比如类的静态变量和内部字符串放入到java堆中。
这里写图片描述

控制参数
-Xms设置堆的最小空间大小。

-Xmx设置堆的最大空间大小。

-XX:NewSize设置新生代最小空间大小。

-XX:MaxNewSize设置新生代最大空间大小。

-XX:PermSize设置永久代最小空间大小。

-XX:MaxPermSize设置永久代最大空间大小。

-Xss设置每个线程的堆栈大小。

垃圾对象的判定

引用计数法

python/android的做法 < sp >
- 解决了:(和Java类似,像是代理模式)
没有初始化
没有及时delete
野指针(指向的对象已经被delete)
- 循环应用
引入弱引用,访问时必须由弱升强

可达性分析

可作为GC Roots的对象包括:
1)虚拟机栈(栈帧中的本地变量表)中引用的对象;
2)方法区中类静态static属性引用的对象;
3)方法区中常量final引用的对象;
4)本地方法栈中JNI(即一般说的Native方法)引用的对象;

因此对于不可达对象判定真正死亡的过程小结如下:
(1)GC进行第一次标记并进行一次筛选(筛选那些覆盖了finalize方法并且finalize方法是第一次调用的对象);–>
(2)另一个低优先级的线程去调用那些被筛选出来的对象的finalize方法;–>
(3)GC进行第二次标记,如果在前一步中那些筛选出来的对象没有在finalize拯救自己,此时,那些未被筛选到的和这些这些筛选到的但是没有拯救自己的对象都将会回收。

垃圾回收算法

是最基础的一种收集算法。分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
缺点:

(1)效率问题:标记和清除的两个过程效率都不高;
(2)空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后需要分配较大对象时,无法找到足够的连续内存而不得不提前出发另一次垃圾收集动作;

标记-整理

标记过程仍然与“标记-清除”算法中一样,但是在标记完成后并不直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

复制
  • 它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存使用完了,就将还存活的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
  • 缺点:将内存缩小为原来的一半,代价较高。
分代收集算法

在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,因此可以选用“复制算法”,此时只需要付出少量存活对象的复制成本即可;对于老年代,因为对象存活率较高、也没有额外空间为期分配担保,就必须使用“标记-清除”或“标记-整理”算法来进行回收。
目前大部分垃圾收集器对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间(一般比例8:1:1),每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间。

原创粉丝点击