JVM之监控JVM

JVM之监控JVM

 

JVM常用的调忧工具

 

  • Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用。对垃圾回收算法有很详细的跟踪。
  • JProfiler:商业软件,需要付费。功能强大。
  • VisualVM:JDK自带,功能强大,与JProfiler类似。推荐。

 

 

监控工具主要分析下面内容

 

  • 堆监控
  • 线程监控
  • 热点分析
  • 生成快照及分析

 

 

堆监控

 

堆信息查看

 

  • 可查看堆空间大小分配(年轻代、年老代、持久代分配)
  • 提供即时的垃圾回收功能
  • 垃圾监控(长时间监控回收情况)

 

堆内类、对象信息查看

 

  • 类、对象的数量
  • 类、对象的类型



 

 

对象引用情况查看



 
 

有了堆信息查看方面的功能,我们一般可以顺利解决以下问题:

 

  • 年老代年轻代大小划分是否合理
  • 内存泄漏
  • 垃圾回收算法设置是否合理

 

 

线程监控 

 

  • 线程信息监控:系统线程数量
  • 线程状态监控:各个线程都处在什么样的状态下



 


Dump线程详细信息

 

  • 查看线程内部运行情况
  • 死锁检查



 

 

 

热点分析

 

  • CPU热点:检查系统哪些方法占用的大量CPU时间
  • 内存热点:检查哪些对象在系统中数量最大(一定时间内存活对象和销毁对象一起统计)

       这两个东西对于系统优化很有帮助。我们可以根据找到的热点,有针对性的进行系统的瓶颈查找和进行系统优化,而不是漫无目的的进行所有代码的优化。



 

 

 

快照

 

快照是系统运行到某一时刻的一个定格。在我们进行调优的时候,不可能用眼睛去跟踪所有系统变化,依赖快照功能,我们就可以进行系统两个不同运行时刻,对象(或类、线程等)的不同,以便快速找到问题。

 

举例说,我要检查系统进行垃圾回收以后,是否还有该收回的对象被遗漏下来的了。那么,我可以在进行垃圾回收前后,分别进行一次堆情况的快照,然后对比两次快照的对象情况。

 

生成快照的方法

 

  • 使用$JAVA_HOME/bin/jmap -dump来触发,eg:jmap -dump:format=b,file=/home/longhao/heamdump.out
  • 使用$JAVA_HOME/bin/jcosole中的MBean,到MBean>com.sun.management>HotSpotDiagnostic>操作>dumpHeap中,点击 dumpHeap按钮。生成的dump文件在java应用的根目录下面。
  • 在应用启动时配置相关的参数 -XX:+HeapDumpOnOutOfMemoryError,当应用抛出OutOfMemoryError时生成dump文件。
  • 使用hprof。启动虚拟机加入-Xrunhprof:head=site,会生成java.hprof.txt文件。该配置会导致jvm运行非常的慢,不适合生产环境。

 

 

 

内存泄漏检查

 

内存泄漏是比较常见的问题,而且解决方法也比较通用,这里可以重点说一下,而线程、热点方面的问题则是具体问题具体分析了。

 

内存泄漏一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而导致新的资源分配请求无法完成,引起系统错误。

 

 

主要的内存问题有:

 

  • 年老代堆空间被占满
  • 持久代被占满
  • 堆栈溢出
  • 线程堆栈满
  • 系统内存被占满

 

 

区别内存泄露和系统超负载

 

内存泄漏和系统超负荷两者是有区别的,虽然可能导致的最终结果是一样的。内存泄漏是用完的资源没有回收引起错误,而系统超负荷则是系统确实没有那么多资源可以分配了(其他的资源都在使用)。

 

注意:内存泄漏对系统危害比较大,因为他可以直接导致系统的崩溃。

 

 

 

年老代堆空间被占满

 

异常:java.lang.OutOfMemoryError: Java heap space

 

说明:每次垃圾回收后,堆被占用的空间都比上一次大,典型的例子是没有关闭数据库连接。


 

解决

 

这种方式解决起来也比较容易,一般就是根据垃圾回收前后情况对比,同时根据对象引用情况(常见的集合对象引用)分析,基本都可以找到泄漏点。

 

 

 

持久代被占满

 

异常:java.lang.OutOfMemoryError: PermGen space

 

说明

 

Perm空间被占满。无法为新的class分配存储空间而引发的异常。这个异常以前是没有的,但是在Java反射大量使用的今天这个异常比较常见了。主要原因就是大量动态反射生成的类不断被加载,最终导致Perm区被占满;还有个可能是JSP太多。

 

更可怕的是,不同的classLoader即便使用了相同的类,但是都会对其进行加载,相当于同一个东西,如果有N个classLoader那么他将会被加 载N次。因此,某些情况下,这个问题基本视为无解。当然,存在大量classLoader和大量反射类的情况其实也不多。

 

解决

  • -XX:MaxPermSize=16m
  • 换用JDK。比如JRocket

 

 

堆栈溢出

 

异常:java.lang.StackOverflowError

 

说明:这个就不多说了,一般就是递归没返回,或者循环调用造成。

 

 

 

线程堆栈满

 

异常:Fatal: Stack size too small

 

说明

java中一个线程的空间大小是有限制的。JDK5.0以后这个值是1M。与这个线程相关的数据将会保存在其中。但是当线程空间满了以后,将会出现上面异常。

 

解决:增加线程栈大小。-Xss2m。但这个配置无法解决根本问题,还要看代码部分是否有造成泄漏的部分。

 

 

 

系统内存被占满

 

异常:java.lang.OutOfMemoryError: unable to create new native thread

 

说明

 

这个异常是由于操作系统没有足够的资源来产生这个线程造成的。系统创建线程时,除了要在Java堆中分配内存外,操作系统本身也需要分配资源来创建线程。因此,当线程数量大到一定程度以后,堆中或许还有空间,但是操作系统分配不出资源来了,就出现这个异常了。

 

分配给Java虚拟机的内存愈多,系统剩余的资源就越少,因此,当系统内存固定时,分配给Java虚拟机的内存越多,那么,系统总共能够产生的线程也就越少,两者成反比的关系。同时,可以通过修改-Xss来减少分配给单个线程的空间,也可以增加系统总共内生产的线程数。

 

解决

  • 重新设计系统减少线程数量
  • 线程数量不能减少的情况下,通过-Xss减小单个线程大小。以便能生产更多的线程。

 

 

垃圾回收的悖论


       所谓“成也萧何败萧何”。Java的垃圾回收确实带来了很多好处,为开发带来了便利。但是在一些高性能、高并发的情况下,垃圾回收确成为了制约Java应 用的瓶颈。目前JDK的垃圾回收算法,始终无法解决垃圾回收时的暂停问题,因为这个暂停严重影响了程序的相应时间,造成拥塞或堆积。这也是后续JDK增加 G1算法的一个重要原因。

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值