Chinaunix首页 | 论坛 | 博客
  • 博客访问: 736626
  • 博文数量: 178
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1507
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-27 23:20
文章分类

全部博文(178)

文章存档

2015年(58)

2014年(121)

我的朋友

分类: Java

2014-11-12 14:31:55

JVM调优

基于Java的应用最大的问题莫过于出现Out Of Memory Error(内存溢出错误),通常出现OOME问题的应用都会有以下一些表现:

l         Jvm crash

l         性能奇差

l         Jvm似乎在不断的进行垃圾回收收集,这通常致使程序停止运行甚至服务崩溃

 

而且一旦出现这种情况,一般都需要重新启动应用服务器。

 

OutOfMemoryError

如果JVM里运行的程序, 它的heap space和perm gen都满了,这个时候程序还企图创建新的对象实例的话,jvm gc就会启动,试图释放足够的内存来创建这个对象。这个时候如果gc无法释放出足够的内存,它就会抛出OutOfMemoryError内存溢出错误。

OutOfMemoryError通常是java内存泄漏引起的。内存泄漏的原因是一个对象虽然不被使用了,但是依然还有对象引用它,因此jvm gc就不会释放它所占据的内存,堆中也就少了块可用的空间。

通常解决这类问题需要从以下两个方面着手:

l         分析内存数据

l         观察堆的增长方式

 

GC工作机制

SUN的jvm内存池被划分为以下几个部分:

Eden Space (heap)

内存最初从这个线程池分配给大部分对象。

 

Survivor Space (heap)

用于保存在eden space内存池中经过垃圾回收后没有被回收的对象。

 

Tenured Generation (heap)

用于保持已经在survivor space内存池中存在了一段时间的对象。

 

Permanent Generation (non-heap)

保存虚拟机自己的静态(reflective)数据,例如类(class)和方法(method)对象。Java虚拟机共享这些类数据。这个区域被分割为只读的和只写的。

 

Code Cache (non-heap)

HotSpot Java虚拟机包括一个用于编译和保存本地代码(native code)的内存,叫做“代码缓存区”(code cache)。

 

简单来讲,jvm的内存回收过程是这样的:

对象在Eden Space创建,当Eden Space满了的时候,gc就把所有在Eden Space中的对象扫描一次,把所有有效的对象复制到第一个Survivor Space,同时把无效的对象所占用的空间释放。当Eden Space再次变满了的时候,就启动移动程序把Eden Space中有效的对象复制到第二个Survivor Space,同时,也将第一个Survivor Space中的有效对象复制到第二个Survivor Space。如果填充到第二个Survivor Space中的有效对象被第一个Survivor Space或Eden Space中的对象引用,那么这些对象就是长期存在的,此时这些对象将被复制到Permanent Generation。

若垃圾收集器依据这种小幅度的调整收集不能腾出足够的空间,就会运行Full GC,此时jvm gc停止所有在堆中运行的线程并执行清除动作。

JVM Tuning 工具

下面是整理的一份JVM调优工具介绍,重点介绍几个关键的:

jps

jps使用很简单,在console输入jps即可,它是用来查看JVM里面所有进程的具体状态, 包括进程ID,进程启动的路径等等。

 

jconsole

jconsole是基于Java Management Extensions (JMX)的实时图形化监测工具,它利用了内建到JVM里面的JMX指令来提供实时的性能和资源的监控,包括了Java程序的内存使用,Heap size, 线程的状态,类的分配状态和空间使用等等。

注意:JBoss 4.0.2及以下版本不支持jconsole,在国际站测试过程中遇到了这个问题,查了JBoss JIRA才知道4.0.2版本的JMX实现并不标准。。。

 

jstat

jstat利用了JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控等等。它包含了以下几个options,能够对gc情况进行详细的监控:

-class

-compiler

-gc

-gccapacity

-gccause

-gcnew

-gcnewcapacity

-gcold

-gcoldcapacity

-gcpermcapacity

-gcutil

-printcompilation

 

我们常用的命令如:

 

jstat -gcutil -t -h10 $jvmpid 1s > _jvmstat_$jvmpid.$now.log &

 

它表示监控jvm gc状态,每秒钟刷新一次。每10次显示一次表头。

这是一个非常实用的工具,对我们jvm的gc状态和监控非常有帮助。对于希望远程监控jvm状态的人,则jstatd比较有用了。

 

jstatd

       jstatd是jstat的守护进程,它能够提供远程jstat功能。使用它的服务需要设置security policy,一种方式是修改${java.home}/jre/lib/security/java.policy文件,在最后加入:

 

grant codebase "file:${java.home}/../lib/tools.jar" {

        permission java.security.AllPermission;

};

 

又或者,定义jstatd.policy文件,加入上面的策略,然后用如下脚本启动jstatd:

jstatd -J-Djava.security.policy=jstatd.policy

 

远程的监控命令:

jstat pid@hostip interval

如:

jstat 1000

 

此时会监控127.0.0.1机器上进程id为1234的jvm gc情况,间隔1秒。

 

还有几个:

jstack

jstack工具可以用来获得java程序崩溃生成的core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息,如果现在运行的java程序呈现挂起的情况,jstack是非常有用的。

目前只有在Solaris和Linux的JDK版本里面才有。

 

jinfo

jinfo可以从core文件里面知道崩溃的Java应用程序的配置信息。目前只有在Solaris和Linux的JDK版本里面才有。

 

jmap

jmap可以从core文件或进程中获得内存的具体匹配情况,包括Heap size, Perm size等等。目前只有在Solaris和Linux的JDK版本里面才有。

 

JVM调优参数

       JVM提供了很多调优参数,在此次调优过程中,我们发现采用以下几个jvm参数会使jvm变得非常稳定,这也是sun官方提供的生产环境调优参数,在sun的很多产品调优脚本中都可以看到这几个参数设置。

标准的JVM GC回收器不会回收Permanent Generation,但JVM提供了并发GC回收器来实现,首先我们要指定回收机制:

 

-XX:+UseConcMarkSweepGC

 

该参数适用于多核并存在缓存机制的应用中。它生成的gc回收曲线变化相比较并行GC而言更加平滑稳定。详细的参数说明可以参考sun的官方文档。

上面的参数是第一步,下一个参数告诉GC回收器能够操作Permanent Generation:

 

-XX:+CMSPermGenSweepingEnabled

 

而GC回收器是不会操作Classes的,这时候我们可以指定以下参数可以使得jvm能够unload class:

 

-XX:+CMSClassUnloadingEnabled

阅读(603) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~