JVM内存监控及性能调优

什么是JVM


基本上来说,JVM是一个虚拟运行环境,对于字节码来说就像是一个机器一样,可以执行任务,并通过底层实现执行内存相关的操作。

JVM使Java程序做到了“一次编写,到处运行”。

JVM解放了程序员,使程序员不必再关系对象的生命周期,使程序员不必再关心应该在何时释放内存。

可以将JVM当做是一种专为Java而生的特殊的操作系统,它的工作是管理运行Java应用程序的运行时环境。

什么是OOM

out-of-memory

系统无法为新线程和新对象分配空间

“堆”满了,垃圾回收不成功

影响:业务宕机

JVM内存模型

 


 



各个年代:

新生代(Young Generation

伊甸园空间(Eden )、幸存者空间(Survivor 

最新被创建的对象会被分配到这里,由于大部分对象在创建后会很快变得不可到达,所以很多对象被创建在新生代,然后消失。

老年代(Old Generation

对象没有变得不可达,并且从新生代中存活下来,会被拷贝到这里。

持久代(Permanent Generation

也被称为方法区(method area)。他用来保存类常量以及字符串常量。

先理解养鱼专业户的“渔池” ?

每个空间的执行顺序如下:

绝大多数刚刚被创建的对象会存放在伊甸园空间。

在伊甸园空间执行了第一次GC之后,存活的对象被移动到其中一个幸存者空间。

  此后,在伊甸园空间执行GC之后,存活的对象会被堆积在同一个幸存者空间。

 当一个幸存者空间饱和,还在存活的对象会被移动到另一个幸存者空间。之后会清空已经饱和的那个幸存者空间。

在以上的步骤中重复几次依然存活的对象,就会被移动到老年代。

 


垃圾回收(GC)是旨在释放不可达Java对象所占用的内存的过程,是Java virtual machineJVM)中动态内存管理系统的核心组成部分。在一个典型的垃圾回收周期中,所有仍被引用的对象,即可达对象,会被保留。没有被引用的Java对象所占用的内存会被释放并回收,以便分配给新创建的对象。

发生在新生代的对象的消失:minor GC(局部垃圾回收)

发生在老年代的对象的消失:major GC(完全垃圾回收)

内存分配

当你在启动Java应用程序时指定了启动参数_-Xmx_(例如,java -Xmx2g MyApp),则相应大小的内存会被分配给Java进程。这块内存即所谓的*Java*(或简称为**)。这块专用的内存地址空间用于存储Java应用程序所创建的对象。随着Java应用程序的运行,会不断的创建新对象并为之分配内存,Java堆(即地址空间)会逐渐被填满。

32位与64位的区别

32JVM最大堆为1.5G

64JVM最大堆为操作系统中内存可使用空间大小

垃圾回收

minor GC

major GC

目标

快速释放不可达对象所占用的内存,防止应用程序出现OOM错误。

回收内存时,对应用程序的性能(指延迟和吞吐量)的影响要尽可能小

原则

JVM堆不是越大越好(堆越大GC时间越长)

不是每个应用程序的JVM配置均可以一样(应用规模、结构和响应要求不一样)

调优的操作是循序渐进的(摸着石头过河)

监控实例

JVM监控工具

命令行:

jstat (关注GC的次数和GC所耗时间)

jmap (将内存堆印象保存为文件)

HeapAnalyzer(分析jmap保存的文件)

图形化

Jconsole

VisualVM

JVM监控工具示例

jstat gc $vmid$ 1000   (vmidjava应用的进程id号,1000:每隔一秒展示GC监控数据)

 

从上图中可计算得到以下值:

年青代GC发生了1989次(YGCT),共耗费了41.001秒(YGC),故年青代每次GC的时间为: 41.001/ 1989= 0.020

完全GC发生了1次(FGCT),共耗费了0.971秒(FGC),故完全GC每次GC的时间为:0.971/1=0.971

一般性能较好的判断:年青代GC耗时在50~100毫秒以内,完全GC小于1秒以内为很好的性能。(因为GC均会影响系统访问)

jmap -dump:format=b,file=testjvm.dump $vmid$

(vmidjava应用的进程id号,filejava堆内存数据保存为文件的名称)

以上的命令可以将当前JAVA内存堆保存为文件,便于进一步进行分析。

特别注意:

进行此工作的时候,应用访问可能会中断。所以不应该在业务运行状态下操作此命令。

JVM分析工具示例

 HeapAnalyzer

命令行:java -Xmx800m -jar ha395.jar

(注意:-Xmx800m 是指定工具所需的java堆大小,此值要大于分析文件的尺寸大小,如果启动过程中发现控制台有 java.lang.OutOfMemoryError出现,可以适当加大上面的数字800,给予更多的空间。ha395.jar中的文件名称按实际下载解压后的文件名为准)

 

JVM监控工具示例

 HeapAnalyzer输出的内容:以下表内容即显示当前系统中出现泄漏的对象(flex/messaging/messages/AsyncMessage)及占用内存的大小。

 

Jconsole

命令行:jconsole.exe server_IP:7080

(注意:Server_IP为运行java程序的服务器IP7080为专门为jconsole远程连接而配置开通的JMX端口。

以下为Windows平台下配置方法:

set JAVA_OPTS=%JAVA_OPTS%  -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=7080 -Dcom.sun.management.jmxremote

)

 

visualVM

JDK1.6以上版本免费提供,服务器上相应配置与Jconsole连接时一样

(注意:Server_IP为运行java程序的服务器IP7080为专门为jconsole远程连接而配置开通的JMX端口。

提示:如visualVMJAVA程序本机运行,可以直接运行监控到,不需对JMX端口进行设置)

 

配置实例

Jconsole监控,HeapDump分析实例

通过以下jconsole监控截图,我们发现应用服务器的堆内存一直在上升。虽然有定时的GC操作(内存回收),但整体趋势仍然是一个斜坡上行的过程。

 

通过以下jconsole监控截图,我们发现应用服务器的堆内存已经占用完,年青代和老年代均没有可进行再分配的空间了,此时执行GC也不能成功。当前应用的状态就是无法访问了。

        再通过其GC时间可看到,Copy(即年青代回收)平均每次为1*60/18646=0.0032秒,没有问题;FullGC4680秒(1小时18分钟)/2304=2.03秒。

由此可以看出,FullGC占用了大量时间和次数,但仍然无法将内存清理出来。证明内存中的某些对象未被成功释放,需要继续分析。


通过heapdump分析工具,发现系统中已经有非常多的flex/messaging/messages/AsyncMessage实例占用了大部分的内存。

由此即定位了是哪个实例出现问题,可以联系开发人员进行配合检查了。


  通过开发人员分析检查,确认flex的消息对象默认没有设置其失效时间,建立的对象将永远不会失效,故就会造成对象不停的建立,直到内存溢出。

    故修改其配置文件,设置相关对象失效时间,达到JAVA可以回收其占用的内存空间,如下:

<destination id="chat">

    <properties>

      <network>

         <subscription-timeout-minutes>30</subscription-timeout-minutes>

      </network>

      <server>

<message-time-to-live>10000</message-time-to-live>              

<allow-subtopics>true</allow-subtopics>

<subtopic-separator>.</subtopic-separator>

      </server>

    </properties>

    <channels>

<channel ref="my-polling-amf"/>

    </channels>

</destination>

JVM参数介绍

以下配置为针对一个特定的应用环境进行的配置:

-Xmx4096m 最大JAVA4G

-Xms4096m  初始化JAVA4G,一般服务器上均设置为最大一样

-Xmn1536M  年青代堆设置值1.5G

-XX:SurvivorRatio=10  年青代中Eden区与Survivor区的比例

-XX:PermSize=250M  持久代的尺寸固化为250M

-XX:MaxPermSize=250M  与上一个设置一致

-XX:+UseParallelOldGC  老年代使用并行回收GC方法,这样可使收集过程中应用仍然提供访问

-XX:MaxTenuringThreshold=30 Survivor区中对象要经过30次复制后仍然有效时,才会移动到老年代

-XX:CMSInitiatingOccupancyFraction=50 老年代占用当达到50%以启动FullGC

JVM参数配置策略

根据操作系统内存使用状况,配置合理的JVM堆大小。一般32位系统不能超过1.5G64位系统可根据应用规模及系统剩余空间调整。并且将XmsXmx设为一样的值;

年青代堆设置一般设置为整个JVM堆的3/8左右;

持久代堆设置一般根据应用程序加载的类、反射的类和调用的方法等情况调整,达到应用长期使用而不报告:java.lang.OutOfMemoryError: PermGen space

特殊配置:

-XX:CMSInitiatingOccupancyFraction=50 老年代占用达50%时启动FullGC

-XX:MaxTenuringThreshold=30 Survivor区中对象要经过30次复制后仍然有效时,才会移动到老年代。一般用于应用中很多对象必须长时间存活的情况,尽量让在这些对象在青年代中被消灭

-XX:+UseParallelOldGC  老年代使用并行回收GC方法,这样可使收集过程中应用仍然提供访问。一般用于应用业务响应要求严格,但此设置效率比较低,并且只能用于多CPU服务器。

猜你喜欢

转载自blog.csdn.net/wypersist/article/details/80550815