欢迎大家访问我的个人网站 萌萌的IT人,后续所有的文章都会在此发布
--------------------------------------------------------------------------------------------
问题描述
通常情况下,对于Java虚拟机出现,只需要配置heap最大最小值,以及maxPermSize,但是这种情况仅限于SUN的Java虚拟机。对于IBM的JVM,情况就完全不一样。
对于Sun的JVM来说,它的GC策略默认是复制、分代算法。也就是说,它会将heap分 成不同的几个区,譬如Solaris JVM中最上面有两个大小相等的区。GC时刻,将一个区的存活对象复制到另外一个对等区,垃圾对象就算遗弃了。这样在heap里面,就不存在碎片问题。另 外Sun的JVM有单独的方法区,也就是Permanent Generation,方法区中保存的一般是Class对象,而不是普通的实例对象,也就是JVM的元数据。
IBM的JVM默认GC策略并没有采取复制、分代。这个可以从GC日志分析出来。它不像Sun的JVM那样,有个单独的方法区,它的方法区就放在Java Heap里面。在IBM的JVM里面,这些对象一般分配在称为k-cluster和p-cluster里(cluster又是属于Heap),而后者一般 是临时在heap里面申请。并且,这些cluster是不能GC,或是被移动重排的(Compact过程)。这就导致Java Heap里面就如同蜂窝,但不同的蜂孔又不能合并,于是,当我们程序里面产生一个大对象,譬如2M的数组(数组必须分配在连续的内存区)时,就没有可分配 空间了,于是就报告OOM。这些不能被移动的cluster之间的空隙就称为所谓的碎片。此时,JVM的Heap利用率可能不到50%。
k-cluster能够存放1280个类对象,第一个p-cluster大小为16K,默 认存放类似于JNI对象和线程对象等不能移动的对象(pinned),然后k-cluster中存放不下的类对象也会放在p-cluster中,第一个p-cluster满了之后,后续的p-cluster大小只有2K,一个类对象大小是256字节
举一个例子
假设我们的系统一共要生成11280个类对象(可能没这么多class,但是同一个class由不同的classloader加载的话,尤其是使用了Spring、Hibernate这些框架的情况下,这些框架经常通过反射创建实例,所 以导致Class对象的数量大大增加),那么除了k簇中存放的1280个之外,其余10000个要放到p簇中。假设初始的16k的p簇中存放的完全是线程 和JNI对象,也就是说我们的类对象要用后来申请的2k一个的p簇来存放。
那么一共需要10000*256/2048 ==1250个p簇
假设我们的堆大小为1G,那么堆内碎片的平均大小是1G/1250,也就是不到1M。这个时候你申请1M以上的内存,就有很大的可能会遇到碎片问题造成的AF。
解决方法
对于IBM的JDK,设置恰当的最大堆和最小堆,设置-Xk和-Xp避免碎片问题,如果程序需要分配大对象较多,那么调整一下LOA的大小(判断标准是gc日志里大量AF是由于分配大于64K内容而产生的,gc日志的分析方法可以看这篇)。
参考参数:-Xk22000 -Xp64k,16K -Xloratio0.2(注意X都为大写)
对于1.5之后的JDK,如果采用默认的optthruput策略或者optavgpause策略,那么也是要设置-Xk和-Xp避免碎片问题,对于gencon策略,因为是分代回收的方式,理论不需要设置-xk -xp参数了,但是IBM没有独立的Permanent Generation,所以一切的调整还是要根据gc日志来。
附Avoiding Java heap fragmentation with Java SDK V1.4.2.翻译版
如何在IBM JDK1.4.2的环境中避免Java堆空间的碎片问题
内容提要:
用户在使用WebSphere Application Server(以下简称WAS)运行自己应用的时候经常会碰到Out Of Memory的问题(简称OOM问题),其中很大一部分的情况是Java堆空间碎片问题引起的OOM问题。IBM JDK 1.4.2的版本中JDK对GC的行为做出了一定的改进。其中一些JDK参数的引进可以改善Java堆空间的碎片问题。
本文首先会给出IBM JDK 1.4.2中对于K簇(k-cluster)和P簇(p-cluster)工作模式的解释。然后在此基础上介绍JDK 1.4.2为解决碎片问题采取的新算法。最后,给出WAS中为改善Java堆空间碎片问题使用的JDK运行参数。
正文:
一、K簇和P簇
在Java堆空间中分配的内存对象通常是可以移动,如果垃圾回收程序(garbage collector)决定重新序列化堆空间的时候,可以四处移动这些对象。然而,有些对象永远或者临时无法移动。这些固定不动的对象就是常说的pin对象 (pinned object)。
在IBM JDK 1.4.2中,垃圾回收程序首先会分配一个K簇作为堆空间底部的第一个对象。K簇是专门用来存储“类块”(class block)的区域。K簇可以容纳1280个类块条目。每个类块的大小是256个字节。紧接着垃圾回收程序会分配一个P簇作为堆空间中的第2个对象。P簇是用来存储pin对象的区域。第一个P簇的默认大小为16KB。
当K簇满了的情况下,垃圾回收程序在P簇中继续分配类块。当P簇满了的情况下,垃圾回收程序会分配一个大小为2KB的新P簇。由于这些新的P簇可以被分配到任何地方而且又不能被移动,这就造成了碎片的问题。
二、pinnedFreeList算法
为了解决这些问题,IBM JDK 1.4.2版本中起用了pinnedFreeList来改变P簇的分配方法。方法的关键是在每一次GC(garbage collection)后,垃圾回收程序从未分配列表的底部分配一些存储区并把它们串到pinnedFreeList上。分配P簇的请求将从pinnedFreeList分配空间,而其他分配内存的请求将从堆的未分配列表上分配。无论堆的未分配列表或者pinnedFreeList被耗尽,垃 圾回收程序都会造成一次分配失败并且引起GC。这种方法确保所有的P簇被分配在堆空间尽可能低的位置。
垃圾回收程序按照如下的算法确定给pinnedFreeList分配多少存储空间:
● 初始分配的空间是50KB
● 如果不是初始分配并且pinnedFreeList为空,那么垃圾回收程序会比较50KB和从上一次GC到现在总共分配P簇大小5倍的数值,按照较大的数值分配
● 如果不是初始分配并且pinnedFreeList不为空,那么垃圾回收程序会比较P簇溢出设定值(默认为2K)和从上一次GC到现在总共分配P簇大小5倍的数值,按照较大的数值分配
这一算法在应用需要加载很多类的情况下会增大pinnedFreeList的大小。这样可以避免由于pinnedFreeList耗尽引起的分配失败。同 时算法在分配很少P簇的情况下会减少pinnedFreeList的大小。这样可以避免pinnedFreeList占用过多的堆空间。
buildPinnedFreeList函数利用上面的算法构建pinnedFreeList。这个函数在如下地方会被调用:
● 在初始化簇(initializeClusters)时
● 在堆空间扩展(expandHeap)结束时
● 在gc0_locked结束时
垃圾回收程序通过调用nextPinnedCluster函数在pinnedFreeList中分配P簇。这个函数的工作方式类似于nextTLH工作方 式:总是从pinnedFreeList获取下一个空的块。如果pinnedFreeList空了,会产生manageAllocFailure。
在realObjCAlloc里,如果在P簇中没有空间了,垃圾回收程序就会调用nextPinnedCluster函数分配一个新的P簇。
在初始化簇(initializeClusters)时,垃圾回收程序调用nextPinnedCluster,nextPinnedCluster会分配一个50K大小的初始P簇,因为pinnedFreeList中唯一的空余块的大小是50K。空余块的大小等于50K是因为pinnedFreeList在初始状态下被设置为50K。
三、调整Java运行参数
对于一个大的Java应用,比如:WAS,默认的K簇可能不足以分配所有的类块。在IBM JDK 1.4.2版本中,可以通过使用-Xk和-Xp命令行参数来设定K簇和P簇的大小,例如:
-Xknnnn
其中nnnn代表K簇中可以容纳的类块的最大数目。通过添加Java的运行是参数-Dibm.dg.trc.print=st_verify 可以在GC的详细信息中得到合适nnnn的值,例如:
<GC(VFY-SUM): pinned=4265(classes=3955/freeclasses=0) dosed=10388 movable=1233792 free=5658>
pinned和classes的数值可以为-Xk的正确数值提供参考。一般推荐使用classes(3955)数值的110%左右,所以在这个例子中-Xk4200是一个合适的设置。
尽管,pinned和classes的数值之间的差值给pCluster的初始大小提供了线索。但是,因为每一个对象可能有不同的大小,所以很难预测P簇所需要的大小和P簇溢出的大小。用户可以通过-Xp命令行参数-Xp设定P簇的初始大小和溢出大小。例如:
-Xpiiii[K][,oooo[K]]
其中,iiii代表P簇的初始大小,单位是KB,oooo是可选的,代表溢出P簇(后续的P簇)的大小。iiii和oooo的默认值为16KB和2KB。
如果用户的应用确实遇到了堆空间碎片的问题,可以考虑打开GC的详细信息并使用-Dibm.dg.trc.print=st_verify参数,并从分析值中得到合适的-Xk值。如果问题依旧存在,可以考虑试验加大P簇的初始大小和溢出大小。
相关推荐
同时,它有助于防止堆空间的碎片化,保持较好的性能。 4. **子池(-Xgcpolicy:subpool)** - 这是一种专为多处理器系统设计的策略,尤其适用于拥有16个或更多处理器的SMP(Symmetric Multi-Processing)系统,如...
IBM JDK5 提供了四种不同的垃圾收集(GC)策略,以适应不同类型的Java应用程序需求。这些策略包括: 1. 针对吞吐量优化(-Xgcpolicy:optthruput):这是默认策略,适用于那些对整体运行速度(吞吐量)要求高于短暂...
总的来说,IBM MAT和JDK8的组合是Java开发和优化过程中不可或缺的工具,对于提升应用程序性能、防止和解决内存泄漏问题具有重要作用。熟练掌握MAT的使用方法,将极大地提升开发者处理复杂内存问题的能力。
【IBM公司Java培训PPT】是一份来自IBM技术中心的教育资源,主要涵盖了Java语言的基础知识,包括其发展历程、主要特性、程序相关问题以及开发环境等内容。以下是对这些知识点的详细说明: 1. **Java语言的发展历史**...
【IBM公司Java培训PPT】深入解析 Java作为一种强大的编程语言,由IBM等大公司广泛支持,其在IT行业中占据着重要地位。本篇将基于IBM的Java培训内容,详细阐述Java语言的核心特点、发展历程、运行机制以及相关开发...
VisualVM是另一个常用的Java性能分析工具,虽然它是Oracle的产品,但在IBM JDK中也常常被使用。它提供了丰富的视图,包括CPU使用率、线程状态、内存分配等,可以进行堆转储分析,找出内存占用大的对象。 JConsole是...
总的来说,华中科技大学与IBM合作的Java培训课件涵盖了Java语言的基础知识,包括其历史、特性、运行机制、程序类型以及开发环境的设置。这些内容对于初学者来说是非常宝贵的资源,可以帮助他们快速掌握Java编程,并...
【IBM Java培训PPT】是IBM公司为提升员工技能而准备的专业资料,这份材料由华中科技大学IBM技术中心负责提供。这份培训涵盖了Java语言的基础知识,包括其发展历程、主要特性、程序开发流程以及相关的技术环境。 ...
【IBM Java培训教程ppt】是针对Java编程语言的一份详细教学资料,涵盖了Java语言的核心概念和发展历程。以下是对其中关键知识点的深入解析: 1. **Java语言的发展历史**: - Java起源于1991年,由James Gosling...
IBM公司的JAVA培训PPT是针对Java编程语言的一份详尽教程,涵盖了从语言的基本概念到其发展历程、主要特性和实际应用等多个方面。这份教程由华中科技大学IBM技术中心制作,旨在帮助学习者深入理解Java这一重要的编程...
【华中科技大学IBM Java培训】是一项深入学习Java编程的教育活动,旨在提升学员对Java语言的理解和应用能力。Java作为一种广泛应用于互联网、企业级应用、移动应用等领域的编程语言,其重要性和价值不言而喻。该培训...
### IBM技术中心Java培训资料知识点总结 #### Java语言概述 - **主要内容提要**: - Java程序的开发环境。 - Java程序相关问题解析。 - Java语言的主要特性和发展历程。 - Java程序的开发流程。 - **Java语言...
【Java语言概述】 Java语言是面向对象的编程语言,由James Gosling领导的Green小组于1991年...华中科技大学IBM技术中心的Java培训资料,无疑为学习者提供了宝贵的资源,帮助他们更好地理解和掌握这一强大的编程语言。
【ha456.jar(IBMHeapAnalyzer)JVM内存分析工具】是一款由IBM开发的专业工具,主要用于诊断Java虚拟机(JVM)的内存问题。它能够解析和分析JVM生成的内存转储文件(通常称为heap dump或hprof文件),帮助开发者识别...
3. **内存碎片**:长时间运行的Java应用可能导致堆内存碎片。碎片化会影响内存效率,因为可用的连续内存块可能太小以容纳新对象。可以通过调整JVM参数,如使用并行或并发GC策略来减少碎片。 **栈内存分析** 1. **...
【IBM Java 教程】是IBM中国研究中心推出的一份专业级的Java培训教程,旨在提升程序员的编程能力和程序的健壮性。这份教程强调在设计程序时,应充分预见可能出现的错误并采取适当的错误处理机制。 Java语言概述: ...
在实际操作中,我们应先通过JDK自带的`jstack`命令生成javacore文件,然后导入IBM Thread and Monitor Dump Analyzer进行深度分析。过程中可能需要多次迭代,调整JVM参数,如增大堆内存、调整垃圾收集策略等,以找到...