今天逛论坛(ITPUB),发现了个2月份的帖子,正好,偶们的系统也要移植到AIX上,启发还是比较大,偶整理了下:
http://www.itpub.net/viewthread.php?tid=942211&extra=&page=1
通常情况下,频繁发生core dump是由于以下两类原因导致
1 内存泄漏
堆内存申请失败通常是由于系统中存在大量不能被GC操作所删除的对象,由于GC只删除没有引用指向的对象,所以,如果在编程的时候没有消除对过期对象的引用(将引用置为null),那么此过期对象就无法被删除。大量的过期对象会导致大量的堆内存被占用。这个问题大多是程序员代码引起的。属于后天问题,是可以优化的。
2 内存碎片问题
通常情况下,对于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字节
内存碎片形成的原因如下:
在GC之后,JVM将无用的对象移除并重新排列,但是由于Class对象无法移除无法重新排列,所以会造成许多的内存碎片。尤其是使用了Spring、 Hibernate这些框架的情况下,这些框架经常通过反射创建实例,所以导致Class对象的数量大大增加,在内存中的位置更加不确定。
…………………………………………………………以下是版主的回答……………………………………………………………………
内容提要:
用户在使用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簇的初始大小和溢出大小。
考虑的建议值:
-Xk20000 -Xp20000K, 256K
IBM JDK 1.5已经重新写了JVM。据说GC算法改了,碎片问题应该会好很多。
……………………………………………………………………………………………………………………………………………………………
也就是说,对于内存溢出的问题,不同jdk解决方式是不一样的,在优化代码的前提下
sun jdk 我们要把最大和最小内存分配一样,这样效率最高,而对于ibm jdk -Xk一般是-Xp的1/10
http://www.itpub.net/viewthread.php?tid=942211&extra=&page=1
通常情况下,频繁发生core dump是由于以下两类原因导致
1 内存泄漏
堆内存申请失败通常是由于系统中存在大量不能被GC操作所删除的对象,由于GC只删除没有引用指向的对象,所以,如果在编程的时候没有消除对过期对象的引用(将引用置为null),那么此过期对象就无法被删除。大量的过期对象会导致大量的堆内存被占用。这个问题大多是程序员代码引起的。属于后天问题,是可以优化的。
2 内存碎片问题
通常情况下,对于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字节
内存碎片形成的原因如下:
在GC之后,JVM将无用的对象移除并重新排列,但是由于Class对象无法移除无法重新排列,所以会造成许多的内存碎片。尤其是使用了Spring、 Hibernate这些框架的情况下,这些框架经常通过反射创建实例,所以导致Class对象的数量大大增加,在内存中的位置更加不确定。
…………………………………………………………以下是版主的回答……………………………………………………………………
内容提要:
用户在使用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簇的初始大小和溢出大小。
考虑的建议值:
-Xk20000 -Xp20000K, 256K
IBM JDK 1.5已经重新写了JVM。据说GC算法改了,碎片问题应该会好很多。
……………………………………………………………………………………………………………………………………………………………
也就是说,对于内存溢出的问题,不同jdk解决方式是不一样的,在优化代码的前提下
sun jdk 我们要把最大和最小内存分配一样,这样效率最高,而对于ibm jdk -Xk一般是-Xp的1/10
相关推荐
JVM初探- 内存分配、GC原理与垃圾收集器,从从提上讲解了jvm中GC的原理、基本的算法和针对不同内存区使用的算法,同时,详细的讲解了当前主要使用的垃圾收集器
主要是JVM内存分配及简单的JVM性能调优
程序运行要用到的内存大于虚拟机能提供的最大内存就发生内存溢出了, 内存溢出的问题要看业务和系统大小而定,对于某些系统可能内存溢出不常见,但某些系统还是很常见的解决的方法
Java 本身提供了多种丰富的工具来帮助开发人员查看和分析 GC 以及 JVM 内存的状况。 输出GC日志 输出 GC 日志对于跟踪分析 GC 的状况,无疑是最明显和直接的分析内存回收状况的方 法,只是 GC 日志输出后需要人肉的...
JVM 内存管理之道 JVM垃圾回收机制 JVM GC组合 JVM 内存监控工具
1.jvm内存结构及功能概述 2.Jvm Heap 内存结构 3.Jvm 的内存分配
JVM内存管理的介绍,编写GC友好的代码。 本材料主要关心 Sun Hotspot JVM 6的内存管理 Sun Hotspot JVM 6的GC模型 主要针对JVM6的GC模型,但也会简单介绍Java 7的G1 编写GC友好代码的一些技巧
JVM性能调优
同时,为了能更深入理解与之相关的知识点,本文特地编写了“第二章 基础知识”,详细的讲解与GC学习相关的JVM架构、JVM选项、Object内存布局、指针压缩等内容,以便读者能更加清晰的理解GC原理的底层逻辑。
jvmgc过程介绍(jpg)
性能测试,线程的 dump 看到线程的 死锁,等待 运行状态
详细介绍了JVM 内存管理相关知识 内存空间( VM运行时数据区域) ◦ 内存结构 ◦ 内存空间 内存分配 内存回收(GC) 内存分析工具
JVM堆相关知识 为什么先说JVM堆? JVM的堆是Java对象的活动空间,程序中的类的对象从中分配空间,其存储着正在运行着的应用程序用到的所有对象。这些对象的建立方式就是那些new一类的操作,当对象无用后,是GC来...
Sun JVM原理与内存管理
mat
java虚拟机jvm及Tomcat中的jvm有关内存的设置与调优
JVM性能调优-JVM内存整理及GC回收
JVM_GC调优
(二)MATJVM 内存分析工具.MAT JVM 内存分析工具.MAT JVM 内存分析工具.(二)MATJVM 内存分析工具.MAT JVM 内存分析工具.MAT JVM 内存分析工具.
jvm 内存监控