编辑推荐: |
本文终点介绍了云环境系统java进程内存占用高和Java类程序的进程优化及处理方案
这两方面内容。
本文来自于rdc.hundsun.com,由火龙果软件Anna编辑、推荐。 |
|
最新的2017年热门编程语言排行榜已经出炉,java排名第一,纵观目前的市场,无论是IT金融软件服务行业或者云业务或大数据行业,java语言是开发的业务程序运用最广泛的语言之一。
本文主要通过分析云系统遭遇的java进程内存溢出的问题,介绍java进程占用系统内存高时的排查方案及建议的解决方案,同时延伸拓展java进程占用系统内存高的原因以及对于linux操作系统的内存管理和优化方案。
【云环境系统java进程内存占用高】
系统的运维值班人员发现该系统的uc注册页面访问超时,根据监控反馈的报错地址,登录相应的UC注册网页时,发现提示如下:网站维护中。
检查该uc注册业务对应的进程后,发现进程运行正常,检查服务的日志情况,然而并发现没有异常。
最后怀疑可能是该服务器的内存溢出,可能是产品对连接到服务端的线程没做控制,导致已结束、假死或超时的线程未释放内存,或者上述线程释放内存之后,没有进行内存整理,产生碎片,然后越积越大,然后就爆炸了。
但是查看服务器的内存情况如下:
通过以上查询发现,服务器内存总共4G,可用的还有300M左右,笔者查询相关资料后使用jmap -dump:format=b,file=ucweb.bin
${pid}的方法dump相应Java进程运行过程中占用的内存情况,然后导出为二进制文件,需要注意的是,这个对性能有影响,其中format=b是通过二进制的意思,通过这个命令把内存结构dump到二进制文件中,然后结合分析软件eclipse来获取具体情况。
也可以通过jmap –heap ${pid}命令来查看该java进程运行时所打印heap的概要信息,GC使用的算法,heap的配置及wise
heap的使用情况。
具体操作方法:
1、使用如下命令查看该业务进程的pid
2、使用jmap –heap 4665来查看该进程的具体使用情况如下:
其中详细描述了该进程的内存占用和配置情况:Heap Configuration是#堆配置情况、Heap
Usage: ##堆使用情况、Eden Space: ##伊甸区、From Space: ##survior1区、To
Space: ##survior2区、concurrent mark-sweep generation:
##老生代使用情况和Perm Generation: ##perm区使用情况。
▲使用ps命令也可以查看该进程的部分资源信息:
ps –p 4655 –o vsz,rss
从上面ps输出的VSZ和RSS分别是3.4G和0.67G,具体分析如下:VSZ是指已分配的线性空间大小,这个大小通常并不等于程序实际用到的内存大小,产生这个空间的可能性很多,比如内存映射,共享的动态库,或者向系统申请了更多的堆,都会扩展线性空间大小;RSZ是Resident
Set Size,常驻内存大小,即进程实际占用的物理内存大小。
对于JVM的几个GC堆和GC也可以使用Jstat这个命令查看:
jstat -gcutil 4655 100 5
其中字段如下:
S0: 年轻代中第一个survivor(幸存区)已使用的占当前容量百分比。
S1: 年轻代中第二个survivor(幸存区)已使用的占当前容量百分比。
E: 年轻代中Eden(伊甸园)已使用的占当前容量百分比。
O: old代已使用的占当前容量百分比。
P: perm代已使用的占当前容量百分比。
YGC: 从应用程序启动到采样时年轻代中gc次数。
YGCT: 从应用程序启动到采样时年轻代中gc所用时间(s)。
FGC: 从应用程序启动到采样时old代(全gc)gc次数。
FGCT: 从应用程序启动到采样时old代(全gc)gc所用时间(s)。
GCT: 从应用程序启动到采样时gc用的总时间(s)。
通过以上显示结果得出此应用程序从启动到采样时具体的参数,如Perm space当前容量的大小和Perm
space已经使用的大小,从而具体来定位是程序在进程运行时占用的内存大小,同时根据这个对该程序在启动的脚本catalina.sh中对的分配空间进行合理的配置:
JAVA_OPTS="-Xms1024m -Xmx2024m -XX:PermSize=128m
-XX:MaxPermSize=256m"
最后通过进程的内存占用资源分析后:是由于永久代内存设置没生效,还是使用默认值,导致内存满了,然后触发fully
gc。
【Java类程序的进程优化及处理方案】
结合以上的案例和分析,大致了解java进程异常时如何进行分析占用的内存和性能资源情况,这部分从java启动时的资源分配到运行时的详细性能跟踪及根据相应机器的配置合理分配对应的内存空间。
一.java进程在启动前的资源分配
只要接触过IT行业的人都知道“java进程运行时占用的内存很大”,很多程序员都有类似的遭遇,而且会认为运行Java程序时使用-Xmx和-Xms参数指定的就是程序将会占用的内存,但实际上只是Java堆对象占用的内存,堆只是影响Java程序占用内存数量的一个因素。要想了解java进程占用内存大的原因,可以先了解是哪些因素会影响到内存的占用。
大致来说,JAVA进程包含如下因素:对象(Objects)、类(Classes)、线程(Threads)、本地数据结构(Native
data structures)、本地代码(Native code)。而且随着程序启动和运行后,上面的这些因素对内存占用的影响又实时根据应用程序、运行业务系统环境和不同的操作系统类型(windows、linux或mac)的不同而发生变化,因此该如何计算总的内存占用量?
想通过各种计算方式使用一个准确的数字是很困难的,因为程序员很难控制自己服务器上的特定参数,但是对照上面的影响因素能控制以下部分:
堆大小:-Xmx
类占用的内存:-XX:MaxPermSize
线程栈:-Xss控制每个线程占用的内存
Xmx是java进程启动的一个配置项,主要用于设置相应业务应用程序(不是整个jvm)运行时能够使用的最大内存数。如果该程序运行的服务器配置不高,但程序运行会占用很大内存时,那就需要修改缺省的设置;特别是配置tomcat的程序时,如果流量、程序都不低的话就需要修改这个缺省值。当然不要大得超过服务器的内存,否则就会出现程序一运行,服务器就挂掉的问题(内存爆掉);反之,如果这个值设置的比较低,每次运行的时候,就会出现内存不够的情况。
Xms是设置内存的另一个重要参数,用它来设置该程序进行初始化时所需要的内存栈的大小。增加这个值的话,程序的启动性能会得到提高。不过同样有前面的限制,并受到Xmx的限制。
XX:MaxPermSize设置过小会导致java.lang.OutOfMemoryError:
PermGen space 会导致内存溢出。
▲内存溢出
1.这一部分内存用于存放Class和Meta的信息,Class在被Load时会放入PermGen
space区域,它和存放Instance的Heap区域不同。
2.GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS
的话,就很可能出现PermGen space错误。
结合以上发现:一般情况下当栈设置的太小时会导致StackOverflow异常,程序出错。
计算内存占用情况的公式如下:
(-Xmx) + (-XX:MaxPermSize) + 线程数 * (-Xss) + 其它内存
其它内存取决于本地代码占用的内存,如NIO、socket缓冲区、JNI等。它一般大约是jvm内存的5%左右。
所以假设我们有下面的JVM参数和100个线程:
-Xmx1024m -XX:MaxPermSize=256m -Xss512k
因此在java程序启动的过程中,可以在启动脚本catalina.sh中定义如上参数的大小:
JAVA_OPTS="-Xms1024m -Xmx2024m -XX:PermSize=128m
-XX:MaxPermSize=256m"
二.如何在JAVA运行过程中查看实时性能
结合以上部分对异常进程的分析和配置,可以了解到最常见的java进程性能资源的分析命令和具体的查看方式,下面大致介绍2种:Jmap和Jsata。
Jmap是一个java进程内存最常见的一个命令,它可以输出所有内存中对象的性能信息,特别是可以将VM
中的heap以二进制形式输出成文本file.bin。打印出指定Java进程(使用pid来区分)内存中的所有‘对象’的情况(如:产生那些对象,及其数量),然后使用分析软件eclipse或者其他的分析工具来分析输出的文本file.bin。
同样Jamp指令有不同的参数和具体的使用方式,这里只是简单说明一下。
例如该java进程的pid信息如下:
jmap –finalizerinfo 4655 -finalizerinfo 打印正等候回收的对象信息
。
jmap –heap 4655 -heap 打印heap的概要信息,GC使用的算法,heap的配置及wise
heap的使用情况。
jmap –histo 4655 -histo[:live] 打印每个class的实例数目,内存占用,类全名信息。VM的内部类名字开头会加上前缀”*”.
如果live子参数加上后,只统计活的对象数量。
jmap -permstat 4655 -permstat 打印classload和jvm heap永久代的信息,包含每个classloader的名字、活泼性、地址、父classloader和加载的class数量。另外,内部String的数量和占用内存数也会打印出来。
Jstat(Java Virtual Machine statistics monitoring
tool)是JDK本身自带的一个轻量级小工具,目录一般在Java的bin下,主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行监控,也包括对Heap
size和垃圾回收状况的监控。
Jstat的功能强大之处体现于众多的可选项,从而可以详细查看堆内各个部分的使用量以及加载类的数量,可以加上具体进程的id来查看相应的具体资源情况,这里也是简单说明一下。
jstat –class 4665 显示加载class的数量,及所占空间等信息。
jstat -compiler 4665 显示VM实时编译的数量等信息。
jstat -gc 4665 显示gc的信息,查看gc的次数和时间。
jstat -gccapacity 4655 显示VM内存中三代(young,old,perm)对象的使用和占用大小。
jstat -gcutil 4655 统计gc信息。
jstat -gcnew 4655 显示年轻代对象的信息。
jstat –gcold 4655 显示old代对象的信息。
jstat -gcoldcapacity 4655 显示old代对象的信息及其占用量。
jstat –gcpermcapacity 4655 显示perm对象的信息及其占用量。
jstat -printcompilation 4655 显示当前VM执行的信息。
|