Java内存组成&GC算法

@(JAVA)[java]

  • Java内存组成GC算法
  • 一内存组成
    • 一Java程序的内存组成

      • 1Java堆
      • 2方法区含常量池永久代
      • 3栈
        • 1Java虚拟机栈
        • 2本地方法栈
      • 4程序计数器
      • 5直接内存
    • 二各种OOM情形模拟
      • 1Java堆溢出
      • 2方法区含常量池溢出
      • 3栈溢出
      • 4直接内存溢出
      • 5其它
  • 二GC算法
    • 一算法基础

      • 1标记判断对象是否生存的算法

        • 1引用次数算法
        • 2可达路径算法
      • 2清除垃圾回收算法
        • 1标记-清除算法
        • 2标记-复制算法
        • 3标记-整理算法
    • 二常用算法
      • 1Serial串行收集器
      • 2ParNew并行收集器
      • 3Parallel Scanvenge简称Parallel也称Throughput吞吐量优先收集器
      • 4ConcurrentMarkSweep
      • 5G1
    • 三GC组合
      • 1-XXUseSerialGC
      • 2-XXUseParNewGC
      • 3-XXUseParallelGC
      • 4-XXUseParllelOldGC
      • 5-XXUseConcMarkSweepGC
      • 6-XXUseG1GC
    • 四ParNew
      • 1重要选项
      • 2日志说明
    • 五CMS
      • 1优缺点
      • 2CMS的基本流程
      • 3CMS完整流程日志
      • 4CMS的重要配置参数
      • 6CMS一个常见的错误concurrent mode failure
    • 六G1
  • 三JVM重要参数
    • 1-Xmngmk
    • 2-Xms -Xmx
    • 3-XXPermSizegmk -XXMaxPermSizegmk
    • 4-Xss
    • 5 -XXNewRatio -XXSurvivorRatio
    • 6client与server模式
    • 7-32与-64
    • 8GC日志打印相关
  • 四常用工具及命令
    • 一最常用命令
    • 二常用命令
      • 1jps
      • 2jstat
        • 1 jstat -gcutil 10763 1000 100
        • 2jstat -gc 27787 1000 10
      • 3jinfo
      • 4jmap 与 jhat结合使用java内存映像工具与分析工具
        • 简单步骤
        • 什么是 Java heap dump
        • 触发 Java heap dump的方法
        • 分析 Java heap dump
      • 5jmap的其它用法
        • 1jmap -heap 15914
        • 2jmap -histo 15914
      • 6jstack
    • 三使用visualvm远程监控java进程以hadoop进程为例
    • 四使用gcviewer分析GC日志

一、内存组成

(一)Java程序的内存组成

* 简单概述:堆用于存放对象实例;方法区(永久代)用于存放常量、类及方法的字节码、方法传递参数等;栈用于存放操作数栈、基本类型数据等。*

1、Java堆

这是Java程序使用最大内存的部分。Java堆是被所有线程共享的内存区域,在虚拟机启动时创建。此内存用于存放对象实例。
Java堆是GC的主要区域,因此也会被称为GC堆。
Java堆被分为新生代和老生代2部分。

2、方法区(含常量池、永久代)

与Java堆类似,这是所有线程共享的内存区域。它包括常量池、域、方法数据、方法和构造方法的字节码、类、实例、接口初始化时用到的特殊方法。
虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但它却有一个别名叫Non-Heap。
很多人把方法区称为永久代,本质上二者并不等价,只是HotSpot把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已。在hotspot中,永久代被放在堆中,并随full GC时被回收,主要回收常量及类的卸载。
对于HotSpot,已经有规划放弃永久代并逐步使用Native Memory来实现方法区了。目前已经把运行时常量池迁出。

3、栈

(1)Java虚拟机栈

Java虚拟机栈是线程私有的。每个方法在执行的同时都会创建一个Stack Frame,用于存储局部变量表、操作数栈、动态链接、方法出入口等信息。

关于堆和栈的说明:堆用于储存各种对象,而栈的局部变量表是保存基本类型的数据以及对象的指针(非对象自身)

(2)本地方法栈

与上面说的Java虚拟机栈作用非常类似,只是Java虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务。

4、程序计数器

程序计数器是线程私有的。
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器的值为空。
此区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

5、直接内存

直接内存并不是虚拟机运行时数据区的一部分。
在NIO中,引入了基于通道与缓冲区的IO方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

Direct Memory不能像新生代、老生代那样,发现内存不足了就通知JVM进行GC,它是等老生代满了,进行full GC时顺便进行回收的,因此过度使用Direct Memory有可能导致OOM
或者可以通过–XX:MaxDirctMemorySize来调整大小

(二)各种OOM情形模拟

1、Java堆溢出

我们创建一个List,然后写入大量的对象直接内存溢出:

public class JavaHeapOOMDemo {public static void main(String[] args) {List<Integer> list = new LinkedList<Integer>();Random random  = new Random();while(true){list.add(new Integer(random.nextInt()));}}
}

运行时加上以下JVM参数:

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

指定了最大的堆内存,并在OOM发生时dump出内存中的内容。运行后console显示:

java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid7268.hprof ...
Heap dump file created [37801092 bytes in 0.652 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceededat com.lujinhong.commons.java.oom.JavaHeapOOMDemo.main(JavaHeapOOMDemo.java:25)

注意第一行GC overhead limit exceeded,每种OOM都有其相应的内容。
使用IBM HeapAnalyzer分析dump出来的结果

发现有一个List对象占用了98.5%的内存,它包含了498788个Integer对象。

发生堆OOM有2种可能:
* 一是内存真的不够分配所需的对象了,这只能高大堆,或者是优化代码。
* 二是内存泄漏了,某些对象无法被GC回收。

2、方法区(含常量池溢出)

错误现象是

Caused by: java.lang.OutOfMemoryError: PermGen space

即永久出错,但JDK7有了变化。

3、栈溢出

一个常见的情况是递归调用时没有终结条件。

public class JavaVMStackSOF {public static int add(int a, int b){return add( a, b);}public static void main(String[] args) {add(1,1);}}

运行时出现以下错误:

Exception in thread "main" java.lang.StackOverflowErrorat com.lujinhong.commons.java.oom.JavaVMStackSOF.add(JavaVMStackSOF.java:13)at com.lujinhong.commons.java.oom.JavaVMStackSOF.add(JavaVMStackSOF.java:13)at com.lujinhong.commons.java.oom.JavaVMStackSOF.add(JavaVMStackSOF.java:13)at com.lujinhong.commons.java.oom.JavaVMStackSOF.add(JavaVMStackSOF.java:13)at com.lujinhong.commons.java.oom.JavaVMStackSOF.add(JavaVMStackSOF.java:13)

这是超出了栈允许的最大深度,并不是OOM。

  • 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError。
  • 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OOM,此时会报OutOfMemoryError: Unable to create new native thread.
    可以通过-Xss来指定这部分内存的大小。

4、直接内存溢出

直接内存容量可以通过-XX:MaxDirectMemorySize指定,如果不指定,则与-Xmx一样。

如果发现OOM之后Dump文件很小,而程序又直接或者间接的使用了NIO,则可以考虑一下是否直接内存溢出了。直接内存溢出时会出现OutOfMemoryError:Direct Buffer memory.这种错误。

5、其它

还有一些其它情况,并不是OOM,但也是资源使用过量,如:
(1)Socket缓冲区

连接过多的话有可能出现IOExecption: Too many open file。此时一般是有一些资源未关闭导致的,如socket, 文件等。一个例子是kafka的producer未使用close(), 而又在不断的新建连接。

二、GC算法

(一)算法基础

当前主流的JVM均使用mark-sweep的算法进行垃圾回收。因此,关于垃圾回收有2个关键的步骤:
* 标记哪些对象已经死亡,即可以回收的。
* 回收被标记的对象。
这部分描述的只是算法的原理,具体实现细节根据JVM的不同而不同。

1、标记:判断对象是否生存的算法

(1)引用次数算法

记录每个对象被多少个其它对象引用,当引用次数变为0时,则这个对象被标记为可回收。这个方法实现简单,高效,但它不能解决对象的循环引用问题:

A.instance = B;
B.instance = A;

上述代码中,A与B是同一个类的对象,它们互相引用。但除了这部分代码以外,它们没有在其余任何地方被引用,因为对应引用来说,它们应该是没用的对象,可以进行回收的。但引用次数算法并不能解决这问题。

(2)可达路径算法

从几个GC root出发,遍历所有对象,当某些对象不能从GC root到达,则认为这个对象已经死掉,可回收。

GC root一般是一些合局的静态成员、表态常量等。

* 关于引用的说明:引用按强弱程度可分为强引用、软引用、弱引用、虚引用。强引用不能被回收,后面3个根据内存的情况以及被标记的次数来决定是否回收。如缓存之类的对象可回收也可不回收的。*

2、清除:垃圾回收算法

当对象被标记为可回收后,下一步就是回收这些对象了(当然会有触发条件,比如内存满了、System.gc()等),下面看一下如何回收。

(1)标记-清除算法

这是最简单的实现方法,就是将内存中标记为可清除的对象删除。这种方法实现简单且高效,但会形成大量的内存碎片,有可能导致大对象无法写入。

(2)标记-复制算法

将内存分成2个部分,每次只使用一个部分。当有垃圾回收需求时,将还生存的对象一次性的全部复制到另一部分内存,原来那部分内存即可直接清空。
这有一个明显的问题是,内存占用多了一倍。

IBM研究发现,新生代的对象符合“朝生夕灭”的特征,即98%以上的对象在第一次GC时就会被回收。因此现在的新生代一般分成3部分: eden, survivor1, survivor2,它们之间的默认比例为8:1:1。
新生代只使用eden及其中一个survivor区,新对象均会在eden区进行分配,当需要GC时,将eden及survivor中还存活的对象一次复制到另一个survivor中。这种方法只浪费了其中10%的内存。

* 此算法是目前主要JVM新生代的主流回收算法 *

(3)标记-整理算法

上述标记-整理算法并不适用于老生代,因为老生代的对象并不符合“朝生夕灭”的特征,而是有很多对象一直存活到程序结束的。而同时为了避免标记-清除算法留下的内存碎片,不再直接清除对象,而是将对象移到内存堆中的前面,整整齐齐的排列。

(二)常用算法

在JDK历史中出现过很多种GC算法,这里只列举出在hostpot中曾经或者现在被广泛使用的算法实现。

1、Serial:串行收集器

(1)应用线程停止工作,Stop-the-word。
(2)单线程进行垃圾回收。
主要包括2种具体的实现:
* Serial收集器:作用于新生代,基于标记-复制算法。
* Serial Old收集器:作用于老生代,基于标记-整理算法。

2、ParNew:并行收集器

(1)应用线程停止工作,Stop-the-word。
(2)多线程进行垃圾回收。
主要包括2咱具体实现:
* ParNew收集器:作用于新生代,基于标记-复制算法。
* Parllel Old收集器:作用于老生代,基于标记-整理算法。

3、Parallel Scanvenge(简称Parallel,也称Throughput)吞吐量优先收集器

(1)可以设置期望GC时间上限,以及GC时间占总时间的比例,以用来控制吞吐量。
(2)仅作用于新生代,对于需要考虑用户交互等待时间的应用,可以考虑使用。

4、ConcurrentMarkSweep

即CMS,下面详细说明。

5、G1

JDK7以后引入的,下面详细说明。

(三)GC组合

以上各种GC算法可以自由组合用于新生代及老生代,JVM参数中提供了常用的组合参数。

1、-XX:+UseSerialGC

新:Serial,老:Serial Old。

2、-XX:+UseParNewGC

新:ParNew,老:Serial Old

3、-XX:+UseParallelGC

新:Parallel ,老:Serial Old

4、-XX:+UseParllelOldGC

新:Parallel, 老:Parallel Old

5、-XX:+UseConcMarkSweepGC

新:ParNew,老:CMS。
说明:当出现Concurrent Mode Failure或者Promotion Failed时,则会切换至ParNew + Serial Old组合。

6、-XX:+UseG1GC

G1收集器并发、并行执行GC。

下面详细说一下目前最常用的几个GC实现。

(四)ParNew

使用-XX:+UseConcMarkSweepGC时,ParNew是默认的YGC方式。

1、重要选项

(1)-XX:MaxTenuringThreshold
GC分代年龄设置,即经过多少次YGC后会被并提升到老生代,缺省值为15。
(2)-XX:UseAdaptiveSizePolicy
动态调整Java堆区各个区域的内存大小,以及GC分代年龄。
(3)-XX:ServivorRation
Eden/Sruvivor的空间比例,默认为8,即8:1:1。

2、日志说明

2016-10-28T20:04:48.613+0800: 10967.643: [GC2016-10-28T20:04:48.613+0800: 10967.643: [ParNew: 860597K->20467K(943744K), 0.0288630 secs] 1120868K->281132K(16672384K), 0.0290730 secs] [Times: user=0.41 sys=0.01, real=0.03 secs]

(1) 2016-10-28T20:04:48.613+0800是GC开始的时间,10967.643是进程启动至今的时间。
(2)[ParNew: 860597K->20467K(943744K), 0.0288630 secs],这是YGC的情况,860597K表示YGC前新生代使用的内存空间,20467K是YGC后新生代的使用的内存空间,943744K是进程为新生代分配的空间。最后一个是指YGC花费的时间。
(3)1120868K->281132K(16672384K), 0.0290730 secs 意思与上面类似,但指的是事个堆的大小情况。上面可以看出YGC时回收了约840M的空间,因此堆被使用的空间也减少了840M左右。
(4) [Times: user=0.41 sys=0.01, real=0.03 secs] 三个时间分别是指用户时间,系统时间以及实际的耗时。

(五)CMS

1、优缺点

先明白一个道理,只是标记阶段是需要STW的,清理阶段是不需要的,因为已经确定了某些对象是没用的,对这些对象进行操作不会影响应用。因此CMS把并发阶段分成了多个步骤,初始标记和最后的重新标记STW,而并发标记和并发预清理可以与用户线程同时运行。

CMS通过细化标记阶段,使得STW时间较短,但它有以下缺点。

(1)Concurrent Mode Failure
需要注意的是,CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。由于CMS并发清理阶段用户线程还在运行着,伴随程序的运行自然还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理掉它们,只好留待下一次GC时再将其清理掉。这一部分垃圾就称为“浮动垃圾”。也是由于在垃圾收集阶段用户线程还需要运行,即还需要预留足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时的程序运作使用。在默认设置下,CMS收集器在老年代使用了68%的空间后就会被激活,这是一个偏保守的设置,如果在应用中老年代增长不是太快,可以适当调高参数-XX:CMSInitiatingOccupancyFraction的值来提高触发百分比,以便降低内存回收次数以获取更好的性能。要是CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”失败,这时候虚拟机将启动后备预案:临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。所以说参数-XX:CMSInitiatingOccupancyFraction设置得太高将会很容易导致大量“Concurrent Mode Failure”失败,性能反而降低。

(2)内存碎片
还有一个缺点,CMS是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会产生大量空间碎片。空间碎片过多时,将会给大对象分配带来很大的麻烦,往往会出现老年代还有很大的空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。为了解决这个问题,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费附送一个碎片整理过程,内存整理的过程是无法并发的。空间碎片问题没有了,但停顿时间不得不变长了。虚拟机设计者们还提供了另外一个参数-XX: CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的。

2、CMS的基本流程

(1)初始标记:从根对象节点仅扫描与根节点直接关联的对象并标记,这个过程必须STW,但由于根对象数量有限,所以这个过程很短暂。
(2)并发标记:与用户线程并发执行,这个阶段紧随初始标记阶段,在初始标记的基础上继续向下追溯标记。这个阶段,应用线程与并发标记线程并发执行,所以应用不会停顿。
(3)并发预清理:与应用线程并发进行。由于上一个阶段执行期间,会出现一些趁机提升至老生代的对象。在这个阶段通过重新扫描,减少下一个阶段重新标记的工作,因为下一个阶段会STW。
(4)重新标记:STW,但很短暂。暂停工作线程,由GC线程扫描在CMS堆中的对象。这个过程主要是在前期标记的基础上,仅对并发标记阶段遭到破坏的对象引用关系进行修复。扫描从根开始。
(5)并发清理:清楚垃圾对象,这个阶段GC线程和应用线程并发执行。
(6)并发重置:这个阶段,重置CMS的数据结构,做好下一次执行GC的准备工作。
结合CMS的GC日志理解会更好,见下面。

3、CMS完整流程日志

从下面的流程可以看出CMS的FULL GC主要经历以下几个步骤:
(1)CMS-initial-mark

2016-10-28T22:45:24.755+0800: 20603.785: [GC [1 CMS-initial-mark: 12722006K(15728640K)] 12827206K(16672384K), 0.0058570 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

(2)CMS-concurrent-mark

2016-10-28T22:45:24.761+0800: 20603.791: [CMS-concurrent-mark-start]

2016-10-28T22:45:25.449+0800: 20604.480: [CMS-concurrent-mark: 0.686/0.689 secs] [Times: user=3.90 sys=0.15, real=0.69 secs]

(3)CMS-concurrent-preclean

2016-10-28T22:45:25.450+0800: 20604.480: [CMS-concurrent-preclean-start]

2016-10-28T22:45:25.483+0800: 20604.513: [CMS-concurrent-preclean: 0.033/0.033 secs] [Times: user=0.03 sys=0.00, real=0.03 secs]

(3-1)CMS-concurrent-abortable-preclean

2016-10-28T22:45:25.483+0800: 20604.513: [CMS-concurrent-abortable-preclean-start]
2016-10-28T22:45:26.197+0800: 20605.228: [GC2016-10-28T22:45:26.197+0800: 20605.228: [ParNew: 943719K->104832K(943744K), 0.0307730 secs] 13671869K->12980931K(16672384K), 0.0310100 secs] [Times: user=0.33 sys=0.10, real=0.03 secs]
2016-10-28T22:45:26.814+0800: 20605.844: [CMS-concurrent-abortable-preclean: 1.197/1.331 secs] [Times: user=2.53 sys=0.21, real=1.33 secs]
2016-10-28T22:45:26.815+0800: 20605.845: [GC[YG occupancy: 527584 K (943744 K)]2016-10-28T22:45:26.815+0800: 20605.845: [GC2016-10-28T22:45:26.815+0800: 20605.845: [ParNew: 527584K->104832K(943744K), 0.0261780 secs] 13405732K->13077072K(16672384K), 0.0263780 secs] [Times: user=0.30 sys=0.06, real=0.02 secs]

(4)CMS-remark

2016-10-28T22:45:26.842+0800: 20605.872: [Rescan (parallel) , 0.0040910 secs]2016-10-28T22:45:26.846+0800: 20605.876: [weak refs processing, 0.0010700 secs]2016-10-28T22:45:26.847+0800: 20605.877: [scrub string table, 0.0007630 secs] [1 CMS-remark: 12972240K(15728640K)] 13077072K(16672384K), 0.0327240 secs] [Times: user=0.37 sys=0.06, real=0.03 secs]

(5)CMS-concurrent-sweep

2016-10-28T22:45:26.848+0800: 20605.878: [CMS-concurrent-sweep-start]
2016-10-28T22:45:28.025+0800: 20607.055: [GC2016-10-28T22:45:28.025+0800: 20607.055: [ParNew: 943510K->104832K(943744K), 0.0237830 secs] 10879313K->10153451K(16672384K), 0.0240310 secs] [Times: user=0.36 sys=0.00, real=0.02 secs]
2016-10-28T22:45:28.432+0800: 20607.463: [CMS-concurrent-sweep: 1.557/1.584 secs] [Times: user=3.46 sys=0.10, real=1.58 secs]

(6)CMS-concurrent-reset

2016-10-28T22:45:28.433+0800: 20607.463: [CMS-concurrent-reset-start]
2016-10-28T22:45:28.507+0800: 20607.537: [CMS-concurrent-reset: 0.074/0.074 secs] [Times: user=0.14 sys=0.05, real=0.08 secs]

完整的日志如下:

2016-10-28T22:45:24.755+0800: 20603.785: [GC [1 CMS-initial-mark: 12722006K(15728640K)] 12827206K(16672384K), 0.0058570 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2016-10-28T22:45:24.761+0800: 20603.791: [CMS-concurrent-mark-start]
2016-10-28T22:45:25.449+0800: 20604.480: [CMS-concurrent-mark: 0.686/0.689 secs] [Times: user=3.90 sys=0.15, real=0.69 secs]
2016-10-28T22:45:25.450+0800: 20604.480: [CMS-concurrent-preclean-start]
2016-10-28T22:45:25.483+0800: 20604.513: [CMS-concurrent-preclean: 0.033/0.033 secs] [Times: user=0.03 sys=0.00, real=0.03 secs]
2016-10-28T22:45:25.483+0800: 20604.513: [CMS-concurrent-abortable-preclean-start]
2016-10-28T22:45:26.197+0800: 20605.228: [GC2016-10-28T22:45:26.197+0800: 20605.228: [ParNew: 943719K->104832K(943744K), 0.0307730 secs] 13671869K->12980931K(16672384K), 0.0310100 secs] [Times: user=0.33 sys=0.10, real=0.03 secs]
2016-10-28T22:45:26.814+0800: 20605.844: [CMS-concurrent-abortable-preclean: 1.197/1.331 secs] [Times: user=2.53 sys=0.21, real=1.33 secs]
2016-10-28T22:45:26.815+0800: 20605.845: [GC[YG occupancy: 527584 K (943744 K)]2016-10-28T22:45:26.815+0800: 20605.845: [GC2016-10-28T22:45:26.815+0800: 20605.845: [ParNew: 527584K->104832K(943744K), 0.0261780 secs] 13405732K->13077072K(16672384K), 0.0263780 secs] [Times: user=0.30 sys=0.06, real=0.02 secs]
2016-10-28T22:45:26.842+0800: 20605.872: [Rescan (parallel) , 0.0040910 secs]2016-10-28T22:45:26.846+0800: 20605.876: [weak refs processing, 0.0010700 secs]2016-10-28T22:45:26.847+0800: 20605.877: [scrub string table, 0.0007630 secs] [1 CMS-remark: 12972240K(15728640K)] 13077072K(16672384K), 0.0327240 secs] [Times: user=0.37 sys=0.06, real=0.03 secs]
2016-10-28T22:45:26.848+0800: 20605.878: [CMS-concurrent-sweep-start]
2016-10-28T22:45:28.025+0800: 20607.055: [GC2016-10-28T22:45:28.025+0800: 20607.055: [ParNew: 943510K->104832K(943744K), 0.0237830 secs] 10879313K->10153451K(16672384K), 0.0240310 secs] [Times: user=0.36 sys=0.00, real=0.02 secs]
2016-10-28T22:45:28.432+0800: 20607.463: [CMS-concurrent-sweep: 1.557/1.584 secs] [Times: user=3.46 sys=0.10, real=1.58 secs]
2016-10-28T22:45:28.433+0800: 20607.463: [CMS-concurrent-reset-start]
2016-10-28T22:45:28.507+0800: 20607.537: [CMS-concurrent-reset: 0.074/0.074 secs] [Times: user=0.14 sys=0.05, real=0.08 secs]

4、CMS的重要配置参数

(1)-XX:CMSInitiatingOccupancyFraction
触发CMS Full GC时的堆使用比例,默认情况为68%。
如果设置过小,则会提高Full GC出现的频率。
如果设置过大,则会有可能导致GC期间,old空间足以容纳新生代提升上来的对象,出现Concurrent Mode Failure,这会触发Serial Old进行Full GC。

(2)-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0
上面说过,由于CMS会导致内存碎片,因此CMS提供了上面的第一个参数,指定每个Full GC后进行整理,但这需要STW,加大了STW时间。
因此作为折衷,CMS提供了第二个参数,指定每多少次Full GC后,才进行一个整理压缩。

(3)-XX:+CMSParallelRemarkEnabled
表示并行remark

(4)-XX:+UseCMSInitiatingOccupancyOnly
表示只在到达阀值的时候,才进行CMS GC

(5)SoftRefLRUPolicyMSPerMB
官方解释是softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap,我觉得没必要等1秒,所以设置成0

(6)-XX:+CMSScavengeBeforeRemark
强制remark之前开始一次minor gc,减少remark的暂停时间,但是在remark之后也将立即开始又一次minor gc。

6、CMS一个常见的错误:concurrent mode failure

(concurrent mode failure): 13122360K->6441708K(15728640K), 223.2066850 secs] 13971757K->6441708K(16672384K), [CMS Perm : 61330K->61330K(131072K)], 223.2069760 secs] [Times: user=218.91 sys=0.10, real=223.22 secs]

基本原因为进程的CMS Full GC时发生concurrent mode failure,出现这种错误时CMS会中止GC,马上转向使用Serial Old进行Full GC,而使用Serial Old需要花费很长很长的时间,这个超长的时间有可能导致某些进程挂掉。

concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。

因此解决办法就是避免在Full GC时,老生代放不下新生代promotion上来的对象,具体可操作的办法包括:
1、【使用此方法】-XX:CMSInitiatingOccupancyFraction:降低触发Full GC的阈值,默认为68%,这里设置为了80%。改加默认的68%。
2、减少新生代的大小。

完整GC日志:

2016-11-30T11:34:08.842+0800: 2832129.747: [GC [1 CMS-initial-mark: 12663697K(15728640K)] 12727632K(16672384K), 0.0131410 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
2016-11-30T11:34:08.885+0800: 2832129.790: [CMS-concurrent-mark-start]
2016-11-30T11:34:09.884+0800: 2832130.789: [GC2016-11-30T11:34:09.884+0800: 2832130.789: [ParNew: 893204K->99658K(943744K), 0.0707600 secs] 13583525K->12789979K(16672384K), 0.0710440 secs] [Times: user=0.66 sys=0.01, real=0.07 secs]
2016-11-30T11:34:10.786+0800: 2832131.691: [GC2016-11-30T11:34:10.786+0800: 2832131.691: [ParNew: 938570K->104832K(943744K), 0.1355030 secs] 13647323K->12889472K(16672384K), 0.1357800 secs] [Times: user=1.08 sys=0.01, real=0.14 secs]
2016-11-30T11:34:11.740+0800: 2832132.645: [CMS-concurrent-mark: 2.621/2.855 secs] [Times: user=22.88 sys=0.31, real=2.85 secs]
2016-11-30T11:34:11.740+0800: 2832132.645: [CMS-concurrent-preclean-start]
2016-11-30T11:34:11.921+0800: 2832132.826: [CMS-concurrent-preclean: 0.163/0.181 secs] [Times: user=0.64 sys=0.00, real=0.19 secs]
2016-11-30T11:34:11.921+0800: 2832132.826: [CMS-concurrent-abortable-preclean-start]
2016-11-30T11:34:11.961+0800: 2832132.866: [GC2016-11-30T11:34:11.961+0800: 2832132.866: [ParNew: 943744K->104832K(943744K), 0.1217300 secs] 13755008K->12985125K(16672384K), 0.1219930 secs] [Times: user=0.94 sys=0.00, real=0.12 secs]
2016-11-30T11:34:12.814+0800: 2832133.719: [CMS-concurrent-abortable-preclean: 0.762/0.893 secs] [Times: user=4.30 sys=0.06, real=0.89 secs]
2016-11-30T11:34:12.835+0800: 2832133.741: [GC[YG occupancy: 584557 K (943744 K)]2016-11-30T11:34:12.836+0800: 2832133.741: [GC2016-11-30T11:34:12.836+0800: 2832133.741: [ParNew (promotion failed): 584557K->567447K(943744K), 0.5155400 secs] 13473043K->13521212K(16672384K), 0.5157840 secs] [Times: user=0.93 sys=0.00, real=0.52 secs]
2016-11-30T11:34:13.352+0800: 2832134.257: [Rescan (parallel) , 1.9185140 secs]2016-11-30T11:34:15.270+0800: 2832136.175: [weak refs processing, 0.0004040 secs]2016-11-30T11:34:15.271+0800: 2832136.176: [scrub string table, 0.0011850 secs] [1 CMS-remark: 12953764K(15728640K)] 13521212K(16672384K), 2.4363850 secs] [Times: user=9.48 sys=0.07, real=2.44 secs]
2016-11-30T11:34:15.272+0800: 2832136.178: [CMS-concurrent-sweep-start]
2016-11-30T11:34:15.540+0800: 2832136.446: [Full GC2016-11-30T11:34:15.541+0800: 2832136.446: [CMS2016-11-30T11:35:03.411+0800: 2832184.317: [CMS-concurrent-sweep: 48.059/48.139 secs] [Times: user=12.80 sys=0.04, real=48.14 secs](concurrent mode failure): 12949885K->9366628K(15728640K), 110.8412530 secs] 13671217K->9366628K(16672384K), [CMS Perm : 85545K->85545K(142604K)], 110.8415460 secs] [Times: user=28.22 sys=0.03, real=110.86 secs]
2016-11-30T11:36:11.101+0800: 2832252.006: [GC2016-11-30T11:36:11.101+0800: 2832252.006: [ParNew: 838912K->62402K(943744K), 0.1140310 secs] 10213732K->9437222K(16672384K), 0.1142900 secs] [Times: user=0.43 sys=0.00, real=0.12 secs]
2016-11-30T11:36:17.830+0800: 2832258.735: [GC2016-11-30T11:36:17.830+0800: 2832258.735: [ParNew: 901314K->70061K(943744K), 0.1077270 secs] 10276134K->9444881K(16672384K), 0.1079440 secs] [Times: user=0.49 sys=0.01, real=0.11 secs]
2016-11-30T11:36:25.404+0800: 2832266.309: [GC2016-11-30T11:36:25.404+0800: 2832266.310: [ParNew: 908973K->73846K(943744K), 0.1772550 secs] 10283793K->9448667K(16672384K), 0.1774900 secs] [Times: user=0.66 sys=0.00, real=0.18 secs]
2016-11-30T11:36:32.468+0800: 2832273.373: [GC2016-11-30T11:36:32.468+0800: 2832273.373: [ParNew: 912758K->44006K(943744K), 0.1259630 secs] 10287579K->9418826K(16672384K), 0.1261750 secs] [Times: user=0.49 sys=0.00, real=0.13 secs]
Heappar new generation   total 943744K, used 505660K [0x00000003e0000000, 0x0000000420000000, 0x0000000420000000)eden space 838912K,  55% used [0x00000003e0000000, 0x00000003fc2d5818, 0x0000000413340000)from space 104832K,  41% used [0x00000004199a0000, 0x000000041c499950, 0x0000000420000000)to   space 104832K,   0% used [0x0000000413340000, 0x0000000413340000, 0x00000004199a0000)concurrent mark-sweep generation total 15728640K, used 9374820K [0x0000000420000000, 0x00000007e0000000, 0x00000007e0000000)concurrent-mark-sweep perm gen total 142604K, used 85823K [0x00000007e0000000, 0x00000007e8b43000, 0x0000000800000000)

(六)G1

三、JVM重要参数

1、-Xmn[g|m|k]

或者使用: -XX:NewSize=[g|m|k] -XX:MaxNewSize=[g|m|k]
分别设置新生代的默认空间大小、最大空间大小,以及若二者相等时使用-Xmn代替。
老生代不需要单独设置,用堆大小减去新生代及永久代大小即是老生代的大小

2、-Xms -Xmx

-Xms:初始堆大小 -Xmx:最大堆大小,默认值为物理内存的1/4
默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制。默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。
上面指定的空间大小为新老生代所共用,默认情况下JVM可以根据应用程序的需要动态的扩展或者收缩。
关注吞吐量及延迟的应用程序应该将-Xms与-Xmx设定为同一值。这是因为无论扩展还是收缩新生代或者老生代空间都要进行Full GC。

3、-XX:PermSize=[g|m|k] -XX:MaxPermSize=[g|m|k]

用于设置永久代的空间大小。

4、-Xss

-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

5、 -XX:NewRatio -XX:SurvivorRatio

  • -XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
  • -XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6

6、client与server模式

-client:把应用当成客户端类程序进行优化。该选项应该在应用启动时使用,对这类应用程序而言,内存占用是最重要的性能标准,远比高吞吐量重要。
-server:把应用当成服务器类程序进行优化。适用于高吞吐量比启动时间和内存占用更重要的应用程序。
目前还有一个较新的选项:
-server -XX:TieredCompilation:结合了二者的优点,可以考虑代替-client。

7、-32与-64

使用32位JVM还是64位JVM由应用程序使用的内存来决定,基本原则如下:
0~2G:32位
2G~32G:使用-d64 -XX:+UserCompressedOops
32G以上:64位
事实上,在Java6 Update18之后,JVM根据堆大小自动启用-XX:+UserCompressedOops,因此配置时2G以内使用-32,2G以上使用-64即可。

8、GC日志打印相关

-XX:+PrintGCDetails:打印GC详细信息
-XX:+PrintGC:打印GC基础信息
+XX:PrintGCTimeStamps/–XX:PrintGCDateStamps:开始执行的时间(基准时间/日期时间)
-XX:PrintGCApplicationStoppedTime:打印GC造成程序暂停的时间
-XX:PrintTLAB:打印TLAB空间的使用情况
-XX:PrintTenuringDistribution:打印每次YGC后新的存活周期的阈值
-XX:+PrintHeapAtGC:打印GC前后详细的堆栈信息
-Xloggc:指定GC日志的输出路径

示例
-Xloggc:/home/lujinhong/jvm/gc-$(date +%Y%m%d-%H%M%S).log -XX:+PrintGCDetails -XX:+PrintGCDateStamps

四、常用工具及命令

(一)最常用命令

jstat -gcutil 10763 1000 100 (显示百分比)
jstat -gc 10763 1000 100 (显示实际大小,单位为k)
jstack -l 48150 >> 1.txt
jmap -dump:file=1.txt 48150 (然后使用ibm HeapAnalyzer分析结果)
jmap -heap 15914

(二)常用命令

1、jps

显示java进程,即使用java命令启动的进程
常用用法
1、jps:显示进程id与进程名称
2、jps -l:显示主类的全名,如果进程执行的是jar包,则输出Jar路径
3、jps -v:输出JVM参数

hadoop@gdc-dn06-formal:~$ jps -lv | grep -i datanode
48150 org.apache.hadoop.hdfs.server.datanode.DataNode -Dproc_datanode -Xmx4096m -Dhadoop.log.dir=/home/hadoop/logs -Dhadoop.log.file=hadoop-hadoop-datanode-gdc-dn06-formal.i.nease.net.log -Dhadoop.home.dir=/home/hadoop/hadoop -Dhadoop.id.str=hadoop -Dhadoop.root.logger=INFO,RFA -Djava.library.path=/home/hadoop/hadoop/lib/native -Dhadoop.policy.file=hadoop-policy.xml -Djava.net.preferIPv4Stack=true -Dlog4j.configuration=log4j_dn.properties -Xmx20480m -Dcom.sun.management.jmxremote -XX:+UseConcMarkSweepGC -XX:-TraceClassUnloading -Dcom.sun.management.jmxremote.port=65302 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -XX:ErrorFile=/home/hadoop/logs/error.log -Dhadoop.security.logger=INFO,RFAS

2、jstat

虚拟机统计信息监视工具

监视gc相关的信息,监控进程10763,每1秒一次,共100次

(1) jstat -gcutil 10763 1000 100

  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT3.52   0.00  29.59  35.64  66.87   3382  675.691     2    0.074  675.7653.52   0.00  35.33  35.64  66.87   3382  675.691     2    0.074  675.7653.52   0.00  41.80  35.64  66.87   3382  675.691     2    0.074  675.7653.52   0.00  47.07  35.64  66.87   3382  675.691     2    0.074  675.7653.52   0.00  51.52  35.64  66.87   3382  675.691     2    0.074  675.7653.52   0.00  60.17  35.64  66.87   3382  675.691     2    0.074  675.7653.52   0.00  73.33  35.64  66.87   3382  675.691     2    0.074  675.7653.52   0.00  85.25  35.64  66.87   3382  675.691     2    0.074  675.7653.52   0.00  96.02  35.64  66.87   3382  675.691     2    0.074  675.7650.00   3.84   5.77  35.64  66.87   3383  675.717     2    0.074  675.7910.00   3.84  11.55  35.64  66.87   3383  675.717     2    0.074  675.7910.00   3.84  18.43  35.64  66.87   3383  675.717     2    0.074  675.7910.00   3.84  31.36  35.64  66.87   3383  675.717     2    0.074  675.791

各个列的意思是
* S0 : S0的使用率
* S1 : S1的使用率。重复一下(详见上面),新生代分为eden,S0, S1三个区域,对象首先分配在eden区,然后经过young GC后放入S0或者S1(二者轮流使用),经过几次young GC还存活的对象会被放到老生代。
* E:eden的使用率。注意到上面第9~10行之间发生了一次young GC,因此当时E还存活的对象被放到了S1,其余对象被清除,同时,S0的对象也到了S1,S0的使用率恢复到了0.
* O : 老生代的使用率。
* YGC:进程起来后到现来发生的YGC次数。
* YGCT:YGC总共花费的时间。因此每次YGC的时间为675.717/3383.时间为秒
* FGC:进程起来后到现来发生的FGC次数。
* FGCT:FGC总共花费的时间。因此每次FGC花费的时间为0.074/2
* GCT:进程起来后到现在GC的总花费时间。

(2)jstat -gc 27787 1000 10

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
39296.0 39296.0 23829.0  0.0   314624.0 88632.7   655360.0   582906.8  131072.0 43506.3 289764 1539.501 1060    60.341 1599.842
39296.0 39296.0  0.0   21878.3 314624.0 213984.4  655360.0   582939.7  131072.0 43506.3 289765 1539.507 1060    60.341 1599.848
39296.0 39296.0  0.0   17420.6 314624.0 26928.7   655360.0   582989.0  131072.0 43506.3 289767 1539.518 1060    60.341 1599.859
39296.0 39296.0 14004.3  0.0   314624.0 167322.2  655360.0   583013.3  131072.0 43506.3 289768 1539.523 1060    60.341 1599.864
39296.0 39296.0  0.0   11592.4 314624.0 309165.1  655360.0   583038.1  131072.0 43506.3 289769 1539.528 1060    60.341 1599.869
39296.0 39296.0  0.0   2172.4 314624.0 134507.1  655360.0   588566.0  131072.0 43506.3 289771 1539.539 1060    60.341 1599.880
39296.0 39296.0 564.6   0.0   314624.0 106047.3  655360.0   588569.4  131072.0 43506.3 289772 1539.542 1060    60.341 1599.883

这里显示的是实际大小,单位是k,上面-gcutil显示的是百分比。

3、jinfo

java配置信息工具,显示jvm参数,类似于jps -v
hadoop@gdc-dn06-formal:~$ jinfo -flags 48150
Attaching to process ID 48150, please wait…
Debugger attached successfully.
Server compiler detected.
JVM version is 24.65-b04

-Dproc_datanode -Xmx4096m -Dhadoop.log.dir=/home/hadoop/logs -Dhadoop.log.file=hadoop-hadoop-datanode-gdc-dn06-formal.i.nease.net.log -Dhadoop.home.dir=/home/hadoop/hadoop -Dhadoop.id.str=hadoop -Dhadoop.root.logger=INFO,RFA -Djava.library.path=/home/hadoop/hadoop/lib/native -Dhadoop.policy.file=hadoop-policy.xml -Djava.net.preferIPv4Stack=true -Dlog4j.configuration=log4j_dn.properties -Xmx20480m -Dcom.sun.management.jmxremote -XX:+UseConcMarkSweepGC -XX:-TraceClassUnloading -Dcom.sun.management.jmxremote.port=65302 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -XX:ErrorFile=/home/hadoop/logs/error.log -Dhadoop.security.logger=INFO,RFAS

4、jmap 与 jhat结合使用:java内存映像工具与分析工具

jmap:将Jvm中的对象dump下来,准备给jhat分析。
jhat: 虚拟机堆转储快照分析工具。一直不成功,使用IBM HeapAnalyzer很方便。

简单步骤

$ jmap -dump:format=b,file=heamdump.out 进程号

详细说明如下:
为了分析java应用的内存泄漏,使用thread dump往往解决不了问题。使用jstat【eg:jstat -gcutil pid 1000 5】工具查看运行的java应用的heap size,perm size ,survivor ratio等,当时你无法知道是什么对象把堆填满了。

什么是 Java heap dump

首先需要搞懂什么是java heap,java heap是分配给实例类和数组对象运行数据区,所有java线程在运行期间共享heap中的数据。Java heap dump相当于java应用在运行的时候在某个时间点上打了个快照(snapshot)。

触发 Java heap dump的方法

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

分析 Java heap dump

  • 使用IBM HeapAnalyzer

    IBM HeapAnalyzer是一款免费的JVM内存堆的图形分析工具,它可以有效的列举堆的内存使用状况,帮助分析Java内存泄漏的原因。使用很简单,先下载一个jar包,然后运行:

    java -Xmx512m -jar ha456.jar heapdump.out

下载地址:https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=4544bafe-c7a2-455f-9d43-eb866ea60091
速度太慢时还可以通过csdn等下载

可以不加最后一个参数,此时只打开软件,然后在UI中打开dump文件即可。
注意-Xmx中的-符号是英文的

  • jhat

    jhat(Java Head Analyse Tool )是用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言OQL,分析相关的应用后,可以通过http://localhost:7000来访问分析结果。

    示例: $JAVA_HOME/bin/jhat -J-Xmx512m dump.out

  • Eclipse MemoryAnalyzer

    Eclipse Memory Analyzer是一个快速并且功能强大的Java heap分析器,能够帮助你查找内存泄漏和减少内存消耗。在File>Acquire Heap Dump>configure>HPROF jmap dump provider设置一下分析应用的JDK,点击相关应用列表来生成heap dump并分析。

    在socket,nio中的有些API中,申请的内存是直接想OS要的,在堆中分析内存是查看不到的,可以通过-XX:MaxDirectMemorySize=来设置应用向OS直接申请的最大内存数。

5、jmap的其它用法

(1)jmap -heap 15914

打印heap空间的概要,这里可以粗略的检验heap空间的使用情况。

输出很简单,第四行起开始输出此进程的JAVA使用的环境。

Heap Configuration:指java应用启动时设置的JVM参数。像最大使用内存大小,年老代,年青代,持久代大小等。

Heap Usage:当时的heap实际使用情况。包括新生代、老生代和持久代。

其中新生代包括:Eden区的大小、已使用大小、空闲大小及使用率。Survive区的From和To同样。

有这个可以很简单的查看本进程的内存使用情况。

可以用于分析堆内存分区大小是否合理,新生代和老生代的大小分配是否合适等。

也许进程占用的总内存比较多,但我们在这里可以看到真正用到的并没有多少,很多都是”Free”。内存使用的堆积大多在老年代,内存池露始于此,所以要格外关心“Old Generation”。

注意 oldsize表示的是老生代的初始大小,不是实际大小

hadoop@gdc-storm07-storm:~/var$ jmap -heap 15914
Attaching to process ID 15914, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.65-b04using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GCHeap Configuration:MinHeapFreeRatio = 40MaxHeapFreeRatio = 70MaxHeapSize      = 1073741824 (1024.0MB)NewSize          = 402653184 (384.0MB)MaxNewSize       = 402653184 (384.0MB)OldSize          = 5439488 (5.1875MB)NewRatio         = 2SurvivorRatio    = 8PermSize         = 134217728 (128.0MB)MaxPermSize      = 134217728 (128.0MB)G1HeapRegionSize = 0 (0.0MB)Heap Usage:
New Generation (Eden + 1 Survivor Space):capacity = 362414080 (345.625MB)used     = 124813128 (119.03107452392578MB)free     = 237600952 (226.59392547607422MB)34.43937056750113% used
Eden Space:capacity = 322174976 (307.25MB)used     = 120391536 (114.81431579589844MB)free     = 201783440 (192.43568420410156MB)37.36836966506052% used
From Space:capacity = 40239104 (38.375MB)used     = 4421592 (4.216758728027344MB)free     = 35817512 (34.158241271972656MB)10.988296359680374% used
To Space:capacity = 40239104 (38.375MB)used     = 0 (0.0MB)free     = 40239104 (38.375MB)0.0% used
concurrent mark-sweep generation:capacity = 671088640 (640.0MB)used     = 342857688 (326.97457122802734MB)free     = 328230952 (313.02542877197266MB)51.08977675437927% used
Perm Generation:capacity = 134217728 (128.0MB)used     = 54027416 (51.524559020996094MB)free     = 80190312 (76.4754409790039MB)40.2535617351532% used

(2)jmap -histo 15914

hadoop@gdc-storm07-storm:~/var$ jmap -histo 24203 | head

 num     #instances         #bytes  class name
----------------------------------------------1:         42048       10496784  [B2:           260        9596320  [I3:         57091        6181096  [C4:         19351        2555984  <constMethodKlass>5:         19351        2485600  <methodKlass>6:          1748        1925064  <constantPoolKlass>7:          1748        1219504  <instanceKlassKlass>

这里会生成一个类的统计报表,此表非常简单,如显示什么类有多少个实例,共占了多少字节等。

其中关于I、B、C等的说明如下

BaseType Character  Type    Interpretation
B   byte    signed byte
C   char    Unicode character
D   double  double-precision floating-point value
F   float   single-precision floating-point value
I   int     integer
J   long    long integer
L<classname>;   reference   an instance of class de><classname>de>
S   short   signed short
Z   boolean     de>truede> or de>falsede>
[   reference   one array dimension

6、jstack

java堆栈跟踪工具
查看各个线程信息
jstack−l48150>>2.txthadoop@gdc−dn06−formal:  jstack -l 48150 >> 2.txt hadoop@gdc-dn06-formal:~ more 2.txt
2015-05-24 11:16:27
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.65-b04 mixed mode):

“DataXceiver for client DFSClient_NONMAPREDUCE_1067049541_1 at /10.160.254.91:59578 [Sending block BP-1320426528-10.120.75.79-136177508
6190:blk_1545471492_1100790319712]” daemon prio=10 tid=0x00007ff12cc5b000 nid=0xa424 runnable [0x00007ff135594000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:79)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:87)
- locked <0x00000003017d1f88> (a sun.nio.ch.Util2)−locked<0x00000003017d1f78>(ajava.util.Collections2) - locked (a java.util.CollectionsUnmodifiableSet)

(三)使用visualvm远程监控java进程(以hadoop进程为例)

1、下载安装
(1)下载visualvm
在官网上下载即可,有mac版
(2)工具—插件,选择感兴趣的插件进行安装
此时若本地有运行java进程,则在本地那里已经可以进行监控分析

2、远程服务器配置
(1)在任意目录建立文件jstatd.all.policy,内容如下:
grant codebase “file:${java.home}/../lib/tools.jar” {
permission java.security.AllPermission;
};

3、运行jstad服务
nohup jstatd -J-Djava.security.policy=jstatd.all.policy &
默认是以1099端口运行

4、连接远程监控
远程—添加jstatd连接,填入ip地址即可

(四)使用gcviewer分析GC日志

使用PrintGCDetail生成的GC日志通常很大,肉眼很难分析出一些有用的结论,因此需要GUI工具来协助。
最有用的应该是java自身提供的gchisto,但这个工具已经很久没更新了,对于一些新的GC类型支持不好,甚至连ParNew都支持不好,因此我们选用gcviewer。

使用非常简单,下载,然后add log文件进去。

Java内存组成GC算法相关推荐

  1. Java内存模型 gc算法_JVM内存模型及GC回收算法

    该篇博客主要对JVM内存模型以及GC回收算法以自己的理解和认识做以记录. 内存模型 GC垃圾回收 1.内存模型 从上图可以看出,JVM分为 方法区,虚拟机栈,本地方法栈,堆,计数器 5个区域.其中最为 ...

  2. JVM内存管理------GC算法精解(五分钟教你终极算法---分代搜集算法)

    转载自   JVM内存管理------GC算法精解(五分钟教你终极算法---分代搜集算法) 引言 何为终极算法? 其实就是现在的JVM采用的算法,并非真正的终极.说不定若干年以后,还会有新的终极算法, ...

  3. JVM内存管理------GC算法精解(五分钟让你彻底明白标记/清除算法)

    转载自  JVM内存管理------GC算法精解(五分钟让你彻底明白标记/清除算法) 相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑 ...

  4. JVM内存管理------GC算法精解(复制算法与标记/整理算法)

    转载自  JVM内存管理------GC算法精解(复制算法与标记/整理算法) 本次LZ和各位分享GC最后两种算法,复制算法以及标记/整理算法.上一章在讲解标记/清除算法时已经提到过,这两种算法都是在此 ...

  5. JVM内存管理–GC算法精解(五分钟让你彻底明白标记/清除算法)

    相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑话说前面哦,这篇文章应该能让各位彻底理解标记/清除算法,不过倘若各位猿友不能在五分钟内 ...

  6. 转载:Java 内存区域和GC机制

    原文链接:http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html 目录 Java垃圾回收概况 Java内存区域 Java对象的访 ...

  7. Java 内存区域和GC机制

    2019独角兽企业重金招聘Python工程师标准>>> 目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 J ...

  8. Java系列笔记(3) - Java 内存区域和GC机制

    目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection, ...

  9. Java内存区域和GC机制

    Java垃圾回收概况 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代 ...

最新文章

  1. component-scan和annotation-driven
  2. python3实现四元数到普通角度的转换程序
  3. Alpha多样性稀释曲线rarefraction curve还不会画吗?快看此文
  4. javaScript由哪些部分组成?
  5. 基于DM8168 EVM的智能视频跟踪系统
  6. Python学习笔记:常用内建模块5
  7. Vivado生成bitstream报错,DRC NSTD-1与DRC UCIO-1]
  8. 全国计算机等级考试题库二级C操作题100套(第91套)
  9. mysql学习笔记14 多表查询初步
  10. Linux服务器安装JavaWeb环境(四) Sentinel,Xxl-Job,Seata
  11. Nginx 默认的日志类型
  12. AI 人才缺失催生跨境猎头:人才年薪高达 300 万,猎头直赚 100 万
  13. 苹果手机其他占内存很大去哪删除_Iphone内存总是不够用?原来这才是正确清理垃圾的方法,长见识了...
  14. 环信php创建群组,【PHP】接入环信创建群组和IM用户
  15. 【Golang】解决Go test执行单个测试文件提示未定义问题
  16. 学python可以做什么职业-Python可以做的5大功能和就职5大高薪职业
  17. linux常用命令-第一篇
  18. Shell 工作原理
  19. VSPE虚拟串口关机蓝屏(BSOD)的解决办法
  20. 编译器处理虚函数的原理

热门文章

  1. 前端面试分享:秋招总结(html和css篇)
  2. jQuery——插入元素节点的方法
  3. C++题解-Leecode 375. 猜数字大小 II——Leecode每日一题系列
  4. Java 折半查询,java之折半查询
  5. oraclde存储过程_Oracle存储过程详解(引用)+补充
  6. shell脚本每日一练(三)
  7. java读取16位深png_读取16位灰度TIFF
  8. python发送qq邮件列表_Python SMTP发送邮件
  9. 搜狗浏览器智慧版_奥维互动地图浏览器下载_奥维互动地图浏览器64位版v7.1.2
  10. python文本分析的开源工具_重磅开源:TN文本分析语言