java内存查看与分析


    业界有众多 壮大的java profile的工具, 比方Jporfiler,yourkit,这些收费的东西我就不想说了,想说的是,其实java自己就提供了众多内存监控的小工具,下面列举的工具只不过一小 部分, 细心探究下jdk的工具,还是蛮故意思的呢:)

    1:gc日志输出

    在jvm启动参数中加入 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimestamps -XX:+PrintGCApplicationStopedTime,jvm将会依照这些参数顺序输出gc概要信息, 详尽信息,gc 工夫信息,gc造成的 利用暂停 工夫 。假如在 方才的参数后面加入参数 -Xloggc:文件路径,gc信息将会输出到指定的文件中 。 其余参数还有

    -verbose:gc和-XX:+PrintTenuringDistribution等 。

    2:jconsole

    jconsole是jdk自带的一个内存 综合工具,它提供了图形界面 。 可以查看到被监控的jvm的内存信息,线程信息,类加载信息,MBean信息 。

    jconsole位于jdk目录下的bin目录,在windows下是jconsole.exe,在unix和linux下是jconsole.sh,jconsole 可以监控当地 利用,也 可以监控远程 利用 。 要监控当地 利用,执行jconsole pid,pid便是运行的java 历程id,假如不带上pid参数,则执行jconsole命令后,会看到一个对话框弹出,上面列出了当地的java 历程, 可以 取舍一个进行监控 。假如要远程监控,则要在远程服务器的jvm参数里加入一些东西,由于jconsole的远程监控基于jmx的,对于jconsole 详尽用法,请见专门介绍jconsle的文章,我也将在博客里专门 详尽介绍jconsole 。

    3:jviusalvm

    在JDK6 update 7之后,jdk推出了另外一个工具:jvisualvm,java可视化 虚构机,它不单提供了jconsole 类似的 性能,还提供了jvm内存和cpu实时诊断,还有手动dump出jvm内存状况,手动执行gc 。

    和jconsole一样,运行jviusalvm,在jdk的bin目录下执行jviusalvm,windows下是jviusalvm.exe,linux和unix下是jviusalvm.sh 。

    4:jmap

    jmap是jdk自带的jvm内存 综合的工具,位于jdk的bin目录 。jdk1.6中jmap命令用法:

    Usage:

    jmap -histo <pid>

    (to connect to running process and print histogram of java object heap

    jmap -dump:<dump-options> <pid>

    (to connect to running process and dump java heap)

    dump-options:

    format=b     binary default

    file=<file>  dump heap to <file>

    Example:       jmap -dump:format=b,file=heap.bin <pid>

    jmap -histo <pid>在屏幕上显示出指定pid的jvm内存状况 。以我本机为例,执行该命令,屏幕显示:

    num     #instances         #bytes  class name

    ----------------------------------------------

    1:         24206        2791864  <constMethodKlass>

    2:         22371        2145216  [C

    3:         24206        1940648  <methodKlass>

    4:          1951        1364496  <constantPoolKlass>

    5:         26543        1282560  <symbolKlass>

    6:          6377        1081744  [B

    7:          1793         909688  <constantPoolCacheKlass>

    8:          1471         614624  <instanceKlassKlass>

    9:         14581         548336  [Ljava.lang.Object;

    10:          3863         513640  [I

    11:         20677         496248  java.lang.String

    12:          3621         312776  [Ljava.util.HashMap$Entry;

    13:          3335         266800  java.lang.reflect.Method

    14:          8256         264192  java.io.ObjectStreamClass$WeakClassKey

    15:          7066         226112  java.util.TreeMap$Entry

    16:          2355         173304  [S

    17:          1687         161952  java.lang.Class

    18:          2769         150112  [[I

    19:          3563         142520  java.util.HashMap

    20:          5562         133488  java.util.HashMap$Entry

    Total        239019       17140408

    为了容易查看,我删掉了一些行 。从上面的信息很容易看出,#instance指的是对象数量,#bytes指的是这些对象占用的内存大小,class name指的是对象类型 。

    再看jmap的dump选项,这个选项是将jvm的堆中内存信息输出到一个文件中,在我本机执行

    jmap -dump:file=c:dump.txt 340

    留神340是我本机的java 历程pid,dump出来的文件 比较大有10几M,并且我只不过开了tomcat,跑了一个很 容易的 利用,且没有任何 拜访, 可以 设想,大型 繁忙的服务器上,dump出来的文件该有多大 。需求晓得的是,dump出来的文件信息是很原始的,绝不 合适人直接观看,而jmap -histo显示的内容又太 容易,例如只显示某些类型的对象占用多大内存,以及这些对象的数量,然而没有更 详尽的信息,例如这些对象分别是由谁 缔造的 。那这么说,dump出来的文件有什么用呢?固然有用,由于有专门 综合jvm的内存dump文件的工具 。

    5:jhat

    上面说了,有众多工具都能 综合jvm的内存dump文件,jhat便是sun jdk6及以上版本自带的工具,位于jdk的bin目录,执行 jhat -J -Xmx512m [file] ,file便是dump文件路径 。jhat内置一个 容易的web服务器,此命令执行后,jhat在命令行里显示 综合 后果的 拜访地址, 可以用-port选项指定端口,具体用法 可以执行jhat -heap查看协助信息 。 拜访指定地址后,就能看到页面上显示的信息,比jmap -histo命令显示的 丰硕得多,更为 详尽 。

    6:eclipse内存 综合器

    上面说了jhat,它能 综合jvm的dump文件,然而所有是文字显示,eclipse memory analyzer,是一个eclipse提供用于 综合jvm 堆dump的插件,它的 综合速度比jhat快, 综合 后果是图形界面显示,比jhat的可读性更高 。其实jvisualvm也 可以 综合dump文件,也是有图形界面显示的 。

    7:jstat

    假如说jmap 偏向于 综合jvm内存中对象信息的话,那么jsta便是 偏向于 综合jvm内存的gc状况 。都是jvm内存 综合工具,但显然,它们是从不同维度来 综合的 。jsat常用的参数有众多,如 -gc,-gcutil,-gccause,这些选项具体作用可查看jsat协助信息,我 时常用-gcutil,这个参数的作用不停的显示目前指定的jvm内存的垃圾收集的信息 。

    我在本机执行 jstat -gcutil 340 10000,这个命令是每个10秒钟输出一次jvm的gc信息,10000指的是 间隔 工夫为10000毫秒 。屏幕上显示如下信息(我只取了第一行,由于是按的 定然频率显示,所以实际执行的时候,会有众多行):

    S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT

    54.62   0.00  42.87  43.52  86.24   1792    5.093    33    7.670   12.763

    额……怎么说呢,要看懂这些信息代表什么意思,还必须对jvm的gc机制有 定然的了解才行啊 。其实假如对sun的 hot spot jvm的gc 比较了解的人,应该很容易看懂这些信息,然而不清晰gc机制的人,有点莫名其妙,所以在这里我还是先讲讲sun的jvm的gc机制吧 。说到gc,其实不只仅只不过java的概念,其 着实java之前,就有众多语言有gc的概念了,gc嘛便是垃圾收集的意思,更多的是一种算法性的东西,而跟具体语言没太大关系,所以对于gc的历史,gc的主流算法我就不讲了,那扯得太远了,扯得太远了便是扯淡 。sun现在的jvm,内存的治理模型是分代模型,所以gc固然是分代收集了 。分代是什么意思呢?便是将对象依照生命周期分成三个 品位,分别是:新生代,旧生代, 长久代 。对象刚开始 调配的时候,大 部分都在新生代,当新生代gc提交被触发后了,执行一次新生代 规模内的gc,这叫minor gc,假如执行了几次minor gc后,还有对象存活,将这些对象转入旧生代,由于这些对象已经 通过了组织的重重考验了哇 。旧生代的gc频率会更低一些,假如旧生代执行了gc,那便是full gc,由于不是 部分gc,而是全内存 规模的gc,这会造成 利用停顿,由于全内存收集,必须 封闭内存,不许有新的对象 调配到内存, 长久代便是一些jvm期间, 根本不会消逝的对象,例如class的定义,jvm 步骤区信息,例如静态块 。需求重要的是,新生代里又分了三个空间:eden,susvivor0,susvivor1,按字面上来 了解,便是伊甸园区,幸存1区,幸存2区 。新对象 调配在eden区中,eden区满时,采纳标记-复制算法,即 审查出eden区存活 的对象,并将这些对象复制到是s0或s1中, 而后清空eden区 。jvm的gc说开来,不只不过这么 容易,例如还有串行收集,并行收集,并发收集,还有着名的火车算法,不过那说得太远了,现在对这个有 大体了解就好 。说到这里,再来看一下上面输出的信息:

    S0       S1       E        O          P       YGC     YGCT    FGC    FGCT     GCT

    54.62   0.00  42.87  43.52  86.24   1792    5.093    33    7.670   12.763

    S0:新生代的susvivor0区,空间 使用率为5462%

    S1:新生代的susvivor1区,空间 使用率为0.00%(由于还没有执行第二次minor收集)

    E:eden区,空间 使用率42.87%

    O:旧生代,空间 使用率43.52%

    P: 长久带,空间 使用率86.24%

    YGC:minor gc执行次数1792次

    YGCT:minor gc 消费的 工夫5.093毫秒

    FGC:full gc执行次数33

    FGCT:full gc 消费的 工夫7.670毫秒

    GCT:gc 消费的总 工夫12.763毫秒

    怎么 取舍工具

    上面列举的一些工具,各有利弊,其实假如在开发环境, 使用什么样的工具是无所谓的, 惟独能得到 后果就好 。然而在生产环境里,却不能乱 取舍,由于这些工具 本身就会 消费大量的系统资源,假如在一个生产服务器压力很大的时候,贸然执行这些工具,可能会造成很意外的状况 。最好不要在服务器本机监控,远程监控会 比较好一些,然而假如要远程监控,服务器端的启动脚本要加入一些jvm参数,例如用jconsloe远程监控tomcat或jboss等,都需求设置jvm的jmx参数,假如仅仅只不过 综合服务器的内存 调配和gc信息,强烈推举,先用jmap导出服务器端的jvm的堆dump文件, 而后再用jhat,或者jvisualvm,或者eclipse内存 综合器来 综合内存状况 。