转 jvisualvm 工具使用 https://www.cnblogs.com/kongzhongqijing/articles/3625340.html

VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带(java启动时不须要特定参数,监控工具在bin/jvisualvm.exe)。
 

1、介绍

VisualVM,可以监控线程,内存状况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的).
 
从界面上看仍是比较简洁的,左边是树形结构,自动显示当前本机所运行的Java程序,还能够添加远程的Java VM,其中括号里面的PID指的是进程ID。OverView界面显示VM启动参数以及该VM对应的一些属性。Monitor界面则是监控Java堆大小,Permgen大小,Classes和线程数量。jdk不一样版本中界面会不太一致,若有的含cpu监控,有的则不含(jdk1.6.0_10未包含)。

 

官网上关于jvisualvm的用法介绍 html

http://docs.oracle.com/javase/6/docs/technotes/tools/share/jvisualvm.html  java

 
做用:JVM和监控的应用程序运行在不一样的服务器上,减轻应用程序的负担,特别是HeapDump的时候,应用常可以续负担很大。 
 

VisualVM使用简单,几乎0配置,功能仍是比较丰富的,几乎囊括了其它JDK自带命令的全部功能。c++

  • 内存信息
  • 线程信息
  • Dump堆(本地进程)
  • Dump线程(本地进程)
  • 打开堆Dump。堆Dump能够用jmap来生成。
  • 打开线程Dump
  • 生成应用快照(包含内存信息、线程信息等等)
  • 性能分析。 :idea: CPU分析(各个方法调用时间,检查哪些方法耗时多),内存分析(各种对象占用的内存,检查哪些类占用内存多)
  • ……
 

2、配置

 
本地监控不须要配置,只要打开某个JAVA程序就会自动的加入到本地监控中。
 
远程监控: 本机的VisualVM就必须和远程的JVM要进行通讯,  Visualvm目前支持两种remote connection方式,分别是jstatd和JMX方式。
远程监控某个中间件时,须要修改中间件的启动文件,添加上关于jmx等的信息。
 
一、远程监控tomcat,jmx方式。
复制代码
服务器 上的 tomcat 配置 jvm 启动参数。
在 tomcat 的 catalina.bat 中添 加以下参数:  JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=192.168.0.237    
-Dcom.sun.management.jmxremote.port=18999
                      -Dcom.sun.management.jmxremote.ssl=false 
                      -Dcom.sun.management.jmxremote.authenticate=false"

上述参数未设用户名与密码登陆。

  客户端VisualVM配置 (我客户端用的是WinXP).
     a.直接反键点击Remote,选择Add Remote Host...
     b.在弹出的界面中输入远程机器的IP地址(192.168.0.237),这个IP地址会加入到Remote节点下.
     c.反键点击这个IP地址,选择Add JMX Connection, 在弹出的界面中输入刚配置的端口号(18999), 这个链接会加入到该IP节点下.
     d.反键点击这个链接,选择Open.git

复制代码

此处参数设置与jconsole工具远程监控tomcat相同。程序员

二、监视websphere服务器JVM的配置github

 http://xjsunjie.blog.51cto.com/999372/1331880web

jconsole & jvisualvm远程监视websphere服务器JVM的配置案算法

 在启动文件里配置。shell

 

三、jstatd 配置。windows

 

 

3、使用

http://zhouanya.blog.51cto.com/4944792/1370017

 

visualVM 插件

https://github.com/irockel/tda

visualVM还可经过扩展增长功能。启动页面时有“visualVM 扩展入门指南”,若是须要哪些插件可看下这里的介绍。

在“工具”-》“插件”-》可用插件项中列出。

 除这些可用插件外,还能够增长第三方的插件扩展功能。

Third Party Plugins:

BTrace Plugin: support for creating, deploying and saving BTrace scripts directly from the VisualVM. Home »

Coherence Plugin: summarized statistics and information for a JMX enabled Coherence cluster. Home »

CRaSH Plugin: support for the CRaSH open source shell for the Java Platform in VisualVM. Home »

OSGi Plugin: basic management of OSGi platforms via JMX. Home »

TDA Plugin: Thread Dump Analyzer is a GUI for analyzing thread dumps generated by the Java VM. Home »

 

其余插件里:

 Buffer Monitor: monitoring usage of direct buffers created by ByteBuffer.allocateDirect and mapped buffers created by FileChannel.map.

 Buffer Pools和MBeans Browser能够经过GUI的方式查看DirectMemory的即时使用状况。

若是是JDK 7及以上版本,能够用jconsole或者jvisualvm的MBean窗口查看java.nio.BufferPool.direct属性。参考: https://www.zhihu.com/question/55033583
 



 

4、使用实例

一、插件“Visual GC"使用。

转自:http://supercharles888.blog.51cto.com/609344/1179790

安装 ”Visual GC"插件:

这个插件是jvisualvm的插件,它很是强大,能够动态的对指定的进程进行监控,而且来经过统计面板来分类显示出各项任务/事件的总时间开销:

安装方法: Tool->Plugin->Available Plugins:

重启Visual VM 以后,就能够看到这个"Visual GC"已经被正确的显示了。

 

实战: 用Visual VM和Visual GC来优化咱们的Eclipse启动:

首先,咱们启动eclipse:

在ps -ef|grep eclipse(windows则是任务管理器)中,咱们能够从看到这个进程id为32561

咱们从Visual VM中找到对应的process id:

咱们切换到 “Visual GC"标签页,它会显示启动eclipse的全部测量数据:

分析:

从上图中咱们能够很明显的看出来,主要的时间开销在如下2方面:

(1)编译时间有点长,用了3.794秒,这个时间主要是用来校验eclipse平台自己的字节码了,因此咱们须要关闭字节码校验,让启动时候不会去校验平台自己(也是java写的)的字节码,为了达到这个目的,咱们只须要在eclipse启动参数中加上-Xverify:none

以下所示,由于咱们用的是Spring Source Tool Suite,因此咱们在STS.ini中增长这一行。

(2)另一个大问题就是类加载时间,它有2部分组成,由于类有2部分组成,一是eclipse平台自带的类,二是它所使用的插件的类文件,咱们能够在eclipse启动的时候关闭没必要要的插件加载来减小类加载时间,方法是Preference->General->Startup and Shutdown

校验结果:

如今咱们把eclipse关闭而且从新打开,这会启动一个新的进程,id为32696,咱们把此次Visual GC的测量图和原来的进行比较:

从这里能够看出来,时间被明显的缩短了,编译时间从3.794秒缩短到2.155秒,提高百分比为43.1%。而类加载时间从18.424秒缩短到10.208秒,提高百分比为44.6%。

额外步骤:

对于一些其余的启动参数,好比初始内存,最大内存,Gem,Perm的参数。

 

二、将堆dump的文件,使用其进行查看。

1)堆dump文件。

 

2)将dump文件传至jvisualvm本机,点击”文件“-》”装入“,选择第一步生成的dump文件。

a.摘要标签

 

可查看dump的各项信息。

文件->装入->堆Dump->检查 -> 查找20保留大小最大的对象,就会触发保留大小的计算,而后就能够类视图里浏览,按保留大小排序了。

对象的大小有两种统计方式:

  • 自己大小(Shallow Size):对象原本的大小。
  • 保留大小(Retained Size): 当前对象大小 + 当前对象直接或间接引用到的对象的大小总和。

看自己大小时,占大头的都是char[] ,byte[]之类的,没什么意思(用jmap -histo:live pid 看的也是自己大小)。因此须要关心的是保留大小比较大的对象,看谁在引用这些char[], byte[]。

 

b.类 标签

 

双击某个类,点击实例视图。

c.实例试图

 

5、远程监控内存泄露、解决内存溢出问题

1)内存泄露、溢出的异同

同:都会致使应用程序运行出现问题,性能降低或挂起。

异:

v内存泄露是致使内存溢出的缘由之一;内存泄露积累起来将致使内存溢出。

v内存泄露能够经过完善代码来避免;内存溢出能够经过调整配置来减小发生频率,但没法完全避免。

2)监测内存泄漏

·内存泄漏是指程序中间动态分配了内存,但在程序结束时没有释放这部份内存,从而形成那部份内存不可用的状况,重启计算机能够解决,但也有可能再次发生内存泄露,内存泄露和硬件没有关系,它是由软件设计缺陷引发的。  

·内存泄漏能够分为4类:

a. 常发性内存泄漏。发生内存泄漏的代码会被屡次执行到,每次被执行的时候都会致使一块内存泄漏。

b.偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操做过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。因此测试环境和测试方法对检测内存泄漏相当重要。

c.一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者因为算法上的缺陷,致使总会有一块仅且一块内存发生泄漏。好比,在类的构造函数中分配内存,在析构函数中却没有释放该内存,因此内存泄漏只会发生一次。

d.隐式内存泄漏。程序在运行过程当中不停的分配内存,可是直到结束的时候才释放内存。严格的说这里并无发生内存泄漏,由于最终程序释放了全部申请的内存。可是对于一个服务器程序,须要运行几天,几周甚至几个月,不及时释放内存也可能致使最终耗尽系统的全部内存。因此,咱们称这类内存泄漏为隐式内存泄漏。

3)Heap dump 分析

每隔一段时间给所检测的java应用作一次heap dump:

wKiom1MZtKTTJ5K3AABJbkv4_d4875.jpg

(或者在响应应用pid上鼠标右键heap dump)弹出如下提示框:

wKioL1MZtKaiSdicAAB6rwX6AqE541.jpg

在应用服务器将此文件下载到jvisual vm所在的机器上,file--load打开此文件,以下面三图所示:

wKiom1MZtSiQgvHBAAF6Dw_4JBI844.jpg

wKioL1MZtQLDKyaOAAO9bvzBju0083.jpg

wKiom1MZtSixQ5WVAAGs96BTilg611.jpg

对比上面三个截图,发现彷佛有个东西在急速飙升,仔细一看是这个对象:org.eclipse.swt.graphics.Image 在第一章图中这个还没排的上,第二次dump已经上升到5181个,第三次就是7845个了。涨速至关快,并且和任务管理器里面看到的GDI数量增涨一致,就是它了。

问题到这儿就比较清楚了,回到代码里面仔细一看能够发现,是某个地方反复的用图片来建立Image对象致使的,改掉之后搞定问题。

到这里其实我想说的是,Java使用起来其实要比C++更容易致使内存泄漏。对于C++来讲,每个申请的对象都必须明确释放,任何没有释放的对象都会致使memleak,这是不可饶恕的,并且这类问题已经有不少工具和方法来解决。可是到了Java里面状况就不一样了,对于Java程序员来讲对象都是不须要也没法主动销毁的,因此通常的思路是:随用随new,用完即丢。不少对象具体的生命周期可能连写代码的人本身也不清楚,或者不须要清楚,只知道某个时刻垃圾收集器会去作的,不用管。但极可能某个对象在“用完即丢”的时候在另外一个不容易发现的地方被保存了一个引用,那么这个对象就永远不会被回收。更加糟糕的是整个程序从设计之初就没有考虑过对象回收的问题,对于C++程序员来讲memleak必然是一个设计错误,可是对Java程序员来讲这只是一个疏忽,并且彷佛没有什么好的办法来避免。今天看到的这个问题是由于GDI泄漏会形成严重后果才被重视,但若是仅仅是形成内存泄漏,那这个程序可能得连续跑上个十天半个月才会发现问题。最后就是,对于c++,错误的代码在测试阶段就能够快速的侦测出哪怕一个byte的memleak并加以改正,可是对于java程序,理论上没有哪一个工具可以知道是否是有泄漏,由于除了做者本身之外没有人可以知道一个被引用的对象是否是应该被销毁,只有经过大量的,长期的压力测试才能发现问题,这是很危险的一件事情。

 

4)解决内存溢出问题

一、java.lang.OutOfMemoryError: PermGen space

JVM管理两种类型的内存,堆和非堆。堆是在JVM启动时建立;非堆是留给JVM本身用的,用来存放类的信息的。它和堆不一样,运行期内GC不会释放空间。若是web app用了大量的第三方jar或者应用有太多的class文件而刚好MaxPermSize设置较小,超出了也会致使这块内存的占用过多形成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改成新部署的,非堆存的内容就会愈来愈多。

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不一样,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,因此若是你的应用中有很CLASS的话,就极可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。若是你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。

wKioL1MZtlHREhrhAAMFKXoTEMw761.jpg

如上图所示,PermGen在程序运行一段时间后超出了咱们指定的128MB,经过Classes视图看到,Java在运行的同时加载了大量的类到内存中。PermGen会存储Jar或者Class的描述信息;因此在class大量增长的同时PermGen超出了咱们指定的范围。为了让应用稳定,咱们须要探寻新的PermGen范围。检测时段时候后(以下图)发现PermGen在145MB左右稳定,那么咱们就获得了稳定的新参数;这样PermGen内存溢出的问题获得解决。

wKiom1MZtrWRVGIQAAMV1WiIwr0717.jpg

 

二、java.lang.OutOfMemoryError: Java heap space

第一种状况是个补充,主要存在问题就是出如今这个状况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。若是内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减少堆到Xms设置的值。因此服务器的Xmx和Xms设置通常应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操做系统有关,通常32位机是1.5g到3g之间,而64位的就不会有限制了。

注意:若是Xms超过了Xmx值,或者堆最大值和非堆最大值的总和超过了物理内存或者操做系统的最大限制都会引发服务器启动不起来。

 

垃圾回收GC的角色,JVM调用GC的频度仍是很高的,主要两种状况下进行垃圾回收:

一个是当应用程序线程空闲;另外一个是java内存堆不足时,会不断调用GC,若连续回收都解决不了内存堆不足的问题时,就会报out of memory错误。由于这个异常根据系统运行环境决定,因此没法预期它什么时候出现。

根据GC的机制,程序的运行会引发系统运行环境的变化,增长GC的触发机会。

为了不这些问题,程序的设计和编写就应避免垃圾对象的内存占用和GC的开销。显示调用System.GC()只能建议JVM须要在内存中对垃圾对象进行回收,但不是必须立刻回收。一个是并不能解决内存资源耗空的局面,另外也会增长GC的消耗。

wKiom1MZuOfBZE4hAAJS5vcnocE082.jpg

 

如何避免内存泄漏、溢出

1)尽早释放无用对象的引用。

好的办法是使用临时变量的时候,让引用变量在退出活动域后自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。

2) 程序进行字符串处理时,尽可能避免使用String,而应使用StringBuffer。

由于每个String对象都会独立占用内存一块区域,如:

1.String str = "aaa";    

2.String str2 = "bbb";    

3.String str3 = str + str2;    

4.// 假如执行这次以后str , str2再不被调用,那么它们就会在内存中等待GC回收;    

5.// 假如程序中存在过多的相似状况就会出现内存错误;  

3) 尽可能少用静态变量。

由于静态变量是全局的,GC不会回收。

4) 避免集中建立对象尤为是大对象,若是能够的话尽可能使用流操做。

JVM会忽然须要大量内存,这时会触发GC优化系统内存环境; 一个案例以下:

1.// 使用jspsmartUpload做文件上传,运行过程当中常常出现java.outofMemoryError的错误,    

2.// 检查以后发现问题:组件里的代码    

3.m_totalBytes = m_request.getContentLength();    

4.m_binArray = new byte[m_totalBytes];    

5.// totalBytes这个变量获得的数极大,致使该数组分配了不少内存空间,并且该数组不能及时释放。    

6.// 解决办法只能换一种更合适的办法,至少是不会引起outofMemoryError的方式解决。    

7.// 参考:http://bbs.xml.org.cn/blog/more.asp?name=hongrui&id=3747  

5) 尽可能运用对象池技术以提升系统性能。

生命周期长的对象拥有生命周期短的对象时容易引起内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,能够考虑分块进行处理,而后解决一块释放一块的策略。

6) 不要在常常调用的方法中建立对象,尤为是忌讳在循环中建立对象。

能够适当的使用hashtable,vector 建立一组对象容器,而后从容器中去取那些对象,而不用每次new以后又丢弃。

7) 优化配置。

a.设置-Xms、-Xmx相等;

b.设置NewSize、MaxNewSize相等;

c.设置Heap size, PermGen space:

 

6、使用过程当中遇到的一些问题与疑问

问题1:从服务器dump堆内存后文件比较大(3.5G左右),加载文件、查看实例对象都很慢,还提示配置xmx大小。在windows上如何配置xmx大小?

 

代表给VisualVM分配的堆内存不够,找到${visualvm}/etc/visualvm.conf (如:C:\Program Files\Java\jdk1.6.0_10\lib\visualvm\etc)这个文件,修改

default_options=”-J-Xms24m -J-Xmx192m“

default_options=”-J-Xms24m -J-Xmx1024m”(

 

再重启VisualVM就好了。

对于“堆 dump”来讲,在远程监控jvm的时候,VisualVM是没有这个功能的,只有本地监控的时候才有。另外,就算是本地监控,它在dump和获得实例的 速度那是至关的慢的。因此鉴于这几个缘由,不建议用VisualVM,而是用jmap加上Mat来分析内存状况。

 

问题2:

 

 

参考资料:

一、http://www.kankanews.com/ICkengine/archives/106440.shtml

二、http://freewind.me/blog/20111023/479.html

三、http://supercharles888.blog.51cto.com/609344/1179790

四、http://zhouanya.blog.51cto.com/4944792/1370017

相关文章
相关标签/搜索