java 1.4.2_14_Sun HotSpot JVM 1.4.2 调优

Sun HotSpot JVM 1.4.2 调优

目录

1. 序言

2. 虚拟机中的"代"

2.1. 性能考虑

2.2. 测量

3. 调整代大小

3.1. 堆的总体大小

3.2. 新生代

3.3. 新生代的保证

4. 收集器类型

4.1. 何时使用吞吐收集器

4.2. 吞吐收集器

4.2.1. 大小自适应

4.2.2. Aggressive堆

4.2.3. 吞吐收集器的测量法

4.3. 何时使用并发收集器

4.4. 并发收集器

4.4.1. 并发的额外开销

4.4.2. 新生代的保证

4.4.3. 完全收集

4.4.4. 漂浮垃圾

4.4.5. 暂停

4.4.6. 并发阶段

4.4.7. 并发收集的测量

4.4.8. 并发收集器的并行次要收集

4.5. 何时使用增量收集器

4.6. 增量收集器

4.6.1. 增量收集器测量

5. 其他考虑事项

6. 总结

7. 其他文档

7.1. 输出示例

7.2. 常见问题

从小型桌面应用到运行在大型服务器的web服务,Java 2平台被广泛的应用。在1.4.1版本的J2SE平台中,引入了2种新的垃圾收集器(garbage collector),现在总共有4种垃圾收集器供我们选择。那么,应该如何选择垃圾收集器?又有哪些因素可以作为选择的依据?本文档描述了垃圾收集器共有的特征,并对于在单线程,stop-the-world的收集器上如何最大限度的利用这些特征给出了调整指导。最后,讨论了其他3种收集器独有的特征以及在4种垃圾收集器中做出选择的一些标准。

对于用户而言,在什么情况下,垃圾收集器会带来性能问题?对于大部分应用来说,垃圾收集器不会带来性能问题,也就是说,即使适垃圾收集器的运行会带来很短的暂停,但是应用还是可以以令人满意的性能运行。但是对于使用了大量的线程、处理器、Socket以及内存的大型应用而言(使用默认的垃圾收集器),情况就不同了。

Amdahl 观察到,大部分工作是无法很好的并行处理的,有些工作总是顺序化的,所以,无法从并行机制中获益。对于J2SE平台来说,也是这样,Java虚拟机从最初一直到1.3.1版本,都没有并行的垃圾收集器,所以,相对于其他的并行应用,垃圾收集器所带来的性能影响在多处理器系统上会有所增长。

下图描述的是一个具有良好弹性的理想系统,如果不考虑垃圾收集的话。红线表示在单处理器系统上的应用,垃圾收集只占用1%的时间,当迁移到有32个处理器的平台上的时候,有超过20%的吞吐量(throughput)的损失;在单处理器系统上垃圾收集时间占10%的应用(不考虑那些令人无法接受的垃圾收集时间),当扩展到32处理器系统上时,吞吐量的损失超过了75%。

392.gif

这表明了,在开发小型应用时可以忽略不计的速度问题,当扩展到大型应用系统时却成为最为突出的性能瓶颈。但是对于这种瓶颈的小小的改良就可能收获性能上的显著提高,所以,对于大型应用来说,调整垃圾收集器是非常有价值的。

对于大部分应用来说,默认的垃圾收集器都是可以满足需要的。其他的几种垃圾收集器因为有一些特殊的行为,使用起来比较复杂。除非应用有特殊需求,一般情况下建议选用默认的垃圾收集器。当然,也有例外情况,对于那些运行在有大量内存和处理器的主机上的大型应用,可以首先尝试aggressive 堆(heap)选项(-XX:+AggressiveHeap),稍后有详细描述。

本文选用J2SE 1.4.2(Sun HotSpot),Sun Solaris操作系统(SPARC平台版本),因为这个平台对于硬件和软件来说都有很好的扩展性。当然了,本文也适用于其他平台,如 Linux,Microsoft Windows, Sun Solaris(X86平台版本)。尽管在不同平台上虚拟机的命令行参数是一样的,但是可能其他平台上的默认值和本文描述的有所差别。

J2SE平台的一个特征就是它为开发人员实现了内存的申请和释放,但是,当垃圾收集成为主要的性能瓶颈时,我们就有必要对它的实现进行深入的了解。垃圾收集器可以对应用使用对象的方式进行一个设定,反映在一些可调整的参数上,通过这些参数,在保证抽象能力的前提下提升了虚拟机的性能。

从运行的程序中,没有可以到达某一对象的指针,那么这个对象就被认为是"垃圾"。最直截了当的垃圾收集算法就是枚举每个可到达的对象,剩下的对象就是可以进行回收的垃圾对象了。这种方案所消耗的时间和活动对象的数量是成比例的,所以,对于要保持大量活动对象的大型应用,显然是不适用的。

从J2SE 1.2开始,虚拟机将几种不同的垃圾收集算法组合在一起使用,就是"分代收集"(generational collection)。在幼儿收集器(naive garbage collection)检查堆中活动对象的同时,分代收集器通过分析一些观测属性来避免额外的工作。

在这些观测属性中最重要的就是幼儿死亡率(infant mortality)。下面图表中的蓝色区域就是对象存活期的典型分布。其中X轴表示对象的存活时间,在分配字节时测量。Y轴表示的是对应存活时间的对象字节总量。左侧的顶点表示对象可能在分配之后很短的时间内就被回收,例如在循环中的枚举对象,仅仅能够存活一个循环。

393.gif

有些对象能够存活很长时间,所以上图的X轴向右延展。例如那些在初始化时就创建并且能够存活直到进程终止的对象。在这两个极端之间,就是一些只在中间计算才存活的对象,就是我们看到的到幼儿死亡率右侧的区域。可能有些应用的对象存活周期分布有些差异,但令人惊讶的是大部分应用都和上图吻合。通过关注主要的"夭折"(die young)对象来进行垃圾收集是行之有效的。

为了针对这种情况进行优化,所以将内存进行分代管理,也就是说内存池保持不同年龄段的对象。在分代管理的内存中,当一个代被对象充满的时候,就在这个代上进行垃圾收集。对象是在新生代(young generation)区域中进行分配,因为大部分对象在这个代中就已经死亡。当新生代被填充满之后,在其上进行一次次要垃圾收集(minor collection),由于在新生代有很高的夭折率,所以次要收集算法针对这种情况进行了优化。这种收集的消耗和被其收集的对象的数量成比例。充满死亡对象的新生代收集起来非常的快。一些仍然存活的对象被移动到旧生代(tenured generation),当旧生代需要进行垃圾收集的时候,就会进行主要垃圾收集(major collection),这种收集方式比起次要收集来要慢得多,因为它涉及了全部的活动对象。

下图显示,次要收集的间隔时间比较长,这样能够确保大部分对象都已经死亡。为了确保次要收集发生的间隔能够足够长,需要新生代有足够的空间,这样才能够使得次要收集充分利用新生代中高夭折率的特点。对于那些对象存活周期分布比较奇特的应用情况就不同了,还有,不合适的代大小设置也会使得在对象死亡之前就不得不进行收集。

默认的垃圾收集器可以应用在小型的和大型的应用,但是它的默认参数设置对于小型应用更高效。对于很多服务器应用来说࿰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值