1、JVM体系结构
HotSpot JVM拥有支持强大功能和功能基础的体系结构,并支持实现高性能和大规模可伸缩性的能力。 例如,HotSpot JVM JIT编译器会生成动态优化。
JVM主要的组件包括 classloader、运行时数据区和执行引擎。
2、调优关键组件
下图紫色高亮部分显示了与性能相关的JVM的关键组件。
在调整性能时,JVM有三个重点关注的组件:
堆是对象数据存储的地方。该区域由启动时选择的垃圾收集器管理。 大多数调优选项都与该区域有关,比如调整堆大小以及根据实际情况选择的最合适的垃圾收集器。 JIT编译器对性能有很大影响,但很少需要使用新版本的JVM进行调优。
3、性能基础
通常,在调优Java应用程序时,重点在于两个主要目标:响应性或吞吐量。
响应性
响应性是指应用程序或系统响应所请求数据的速度。例如:
吞吐量
吞吐量专注于在特定时间段内最大限度地提高应用程序的工作量。例如:
什么是自动垃圾收集呢?
自动垃圾收集是查看堆内存的过程,识别哪些对象正在使用,哪些没有,以及删除未使用的对象。 一个正在使用的对象或一个被引用的对象,意味着你的程序的某个部分仍然保持着一个指向该对象的引用。 未使用的对象或未被引用的对象不再被程序的任何部分引用。 所以未被引用对象所使用的内存可以被回收。
在C程语言中,分配和释放内存是一个手动过程。 在Java中,释放内存的过程由垃圾收集器自动处理。 基本过程描述如下。
第一步:标记(Marking)
第一步就是找出哪些内存片段在使用,哪些没有用了。
第二部:正常删除
正常删除会删除掉标记过程中标记的未被引用的对象。
删除未被引用的对象后,内存分配器会保存可以分配新对象的可用空间块的引用。
第三部:压缩
为了进一步提高性能,除了删除未引用的对象之外,还可以压缩剩余的引用对象。 通过将引用对象移动到一起,这可以使得新的内存分配变得更加容易和快速。
为什么要分代收集?
如前所述,标记和压缩JVM中的所有对象效率不高。 随着越来越多的对象被分配,垃圾收集的时间也越来越长。 然而,应用程序的经验分析表明,大多数对象都是短生命周期的。
从上图可以看到,随着时间的推移,越来越少的对象保持着分配( remain allocated)的状态,大多数对象都是短生命周期的。
为了增强JVM的性能,堆内存被分解成了几块,采用分代式管理:年轻带,老年代和永久代。
年轻代:刚刚被new 出来的对象被分配在此区域。内存管理使用minor garbage collection(小GC).
老年代:新生代中执行小粒度的GC幸存下来的”老”对象,内存管理使用major garbage collection(大GC).
永久代:包含应用的类/方法信息, 以及JRE库的类和方法信息.
小GC:执行非常频繁, 而且速度特别快.
大GC:一般会比小GC慢十倍以上.
Stop the World:中断程序运行, 直至GC完成,大小GC都会发出”Stop the World”事件。
1、创建新的对象
每当我们使用new创建一个对象时, 这个对象会被分配到新生代的Eden区域。
2、当Eden区域满时
当Eden区域满时,就触发小GC。
引用可达的对象会移到Survivor(幸存者)区域–S0, 然后清空Eden区域, 此时引用不可达的对象会直接删除。
3、Eden再次满时
当Eden区域再次分配完后, 小GC执行, 引用可达的对象会移到Survivor(幸存者)区域, 而引用不可达的对象会跟随Eden的清空而删除回收.
这次引用可达的对象移动到的是S1的幸存者区, S0区域也会执行小GC, 将其中还引用可达的对象移动到S1区, 且年龄+1. 然后清空S0, 回收其中引用不可达的对象。
此时, 所有引用可达的对象都在S1区, 且S1区的对象存在不同的年龄。
当Eden又满时, S0和S1的角色互换。
4、当Survivor区的对象年龄达到”老年线”时
经过多次小GC后,Survivor区的对象年龄持续增长, 当其中某些对象年龄达到”老年线”, 例如8岁时, 它们会”晋升”到老年区。
随着小GC继续发生,对象将继续被提升到老一代空间。
以上就是年轻代的整分配回收过程。 最终,将对老年代进行一次大GC来清理和整理该空间。
VM参数 | 参数描述 |
---|---|
-Xms | 设置初始堆大小 |
-Xmx | 设置堆最大值 |
-Xmn | 设置年轻代空间大小 |
-XX:PermSize | 设置永久代初始大小 |
-XX:MaxPermSize | 设置永久代最大值 |
-XX:SurvivorRatio | 设置Eden区和survivor区的大小比例,默认是 8。 |
-XX:NewRatio | 设置老年代/年轻代比例,默认是2 |
参考:
Java Garbage Collection Basics