Java虚拟机内存模型及垃圾回收监控调优

Java虚拟机内存模型及垃圾回收监控调优html

     若是你想理解Java垃圾回收若是工做,那么理解JVM的内存模型就显的很是重要。今天咱们就来看看JVM内存的各不一样部分及若是监控和实现垃圾回收调优。java

JVM内存模型        算法

 

   正如你上图所看到的,JVM内存能够划分为不一样的部分,广义上,JVM堆内存能够划分为两部分:年轻代和老年代(Young Generation and Old Generation)编程

年轻代(Young Generation)服务器

年轻代用于存放由new所生成的对象。当年轻代空间满时,垃圾回收就会执行。这个垃圾回收咱们称之为 最小化垃圾回收(Minor GC)。年轻代又能够分为三分部: 一个Eden内存区(Eden Memory)和两个Survivor 内存区(Survivor Memory)多线程

 

关于年轻代的重点:并发

  • 大多数新建立的对象都存放在Eden内存区。
  • Eden区存满对象时,最小化GC将会被执行,全部存活的对象被移到其中一个Survivor区。
  • 最小化GC同时也会检查存活的对象并将它们移到另外一个Survivor区,因此在一段时间,其中一个Survivor区老是空的。
  • 存活的对象通过屡次GC后,将会被移到老年代(Old Generation)一般年轻代转化多长时间变为老年代都会设置一个阀值。

老年代(Old Generation)oracle

   老年代内存包含那些通过屡次最小化GC且存活的对象。 一般当老年代内存满时垃圾回收会被执行。咱们称之为大GC (Major GC),一般这个过程会花费很长的时间。jvm

Stop the World Eventjsp

全部的垃圾回收都是“阻塞”事件(“Stop the World” events) ,由于全部应用程序线程必须中止,直到垃圾回收操做完成以后才能继续。

因为年轻代老是保存着短时间存活的对象,最小化GC很是快,应用程序也不会受到影响。然而大GC(Major GC)因为它要检查全部存活的对象,因此须要花费很长的时间。 大GC会在垃圾回收期间使得你的应用程序没有任何响应,应最大化的减小此类GC。若是你有一个即时响应应用程序且老是有不少的大GC在执行。你会发现存在超时错误。

垃圾回器扫行的时间依赖于GC所使用的策略。这就是为何对于那些高响应用程序来讲,GC的监控与调优显得很是必要。

永久代(Permanent Generation)

永久代或持久代包含JVM用来描述应用程序中使用的类和方法的元数据。注意 永久代不是JAVA堆内存的一部分。

JVM在运行期间依据应用程序所使用的类来存入永久代,同时也包含Java SE库类各方法。 永久代中的对象经过全GC(Full GC)来进行垃圾回收。

方法区Method Area

方法区是永久代的一部分,用于存储类结构(运行时的常量和静态变量)及方法和构造的代码。

运行时常量池Runtime Constant Pool

运行时常量池是类中常量池在编译期的表示,它包含类的运行时常量,静态方法,它是方法区的一部分。

Java栈内存Java Stack Memory

Java 栈内存用于执行线程。包含方法短时间存活的特定值及方法中所涉及的指向堆中其它对象的引用。

Java 堆内存Switches(Java Heap Memory Switches)

 提供了大量的内存Switch,咱们能够用来设置内存大小及它们的比率。一此经常使用的内存Switches以下。

 

VM Switch VM Switch 描述
-Xms 设置JVM启动时初始值。
-Xmx 设置堆的最大值
-Xmn 设置年轻代的大小
-XX:PermGen 设置永久代内存的初始值
-XX:MaxPermGen 设置永久代内存的最大值
-XX:SurvivorRatio 用于提供Eden区和Survivor区的比例, 例如,若是年轻代的大小为 10M,VM switch is -XX:SurvivorRatio=2 那么 5 M 分配给 Eden 区,每个Survivor 区为 2.5 M .默认比例大小为  8。
-XX:NewRatio 老年代/新生代的比例. 默认值是 2.

 

  大多数状况下,上述选项是很是有用的。若是你也想试试其它参数能够查看 JVM 官方主页

 JAVA GC

  Java GC是从内存中标记、移除非可用对象并释放所分配的空间用于后续建立对像的过程。Java编程语言最大的功能之一就是自动垃圾回收。不像其它相似C的编程语言,它们的内存分配与回收能够人为操做。

  GC是后台执行用于检查内存中的全部对象并找出未被任务程序所引用的对象。全部这些未引用的对象将被删除,同时空间也会被回收用于分配给其它对象。

 关于标记、删除方法有两个问题:

1.因为新建立的对象将会变成不可用,全部效率上不是很高。

2.屡次GC后可用的对象很能在后续的GC后仍然可用。

 上述方法的不足在于Java的GC是分代的,在堆内存中分年轻代和老年代。 前面我已经解释过基于最小化GC(Minor GC)和大GC(Major GC)对象是若是被扫描并从一个分代区移到别一个分区。

Java GC的类型

在应用程序中咱们可使用以下五种类型的GC。咱们可使用JVM相关设置为应用程序开启GC策略,如今咱们就来具体的看看.

  1. 串行GC (Serial GC -XX:+UseSerialGC): 串行GC为年轻代和老年代GC提供简单的标记-清除-压缩方法。串行GC在独立应用程序运行的少许CPU的客户机器上很是有效。对于那些低内存占用的应用程序很是有利。
  2. 并行GC (Parallel GC -XX:+UseParallelGC): 并行GC中大部分实现与串行GC相同,除了年轻代的垃圾回收使用N个线程,N是系统CPU内核的数量。咱们能够经过 JVM 的 -XX:ParallelGCThreads=n 选项来控制线程的数量。并行的垃圾回收器由于使用多CPU来加速GC的实现因此也称为并行收集器(throughput collector).并行GC使用单线程来处理老年代的垃圾回收.
  3. 并行Old GC (Parallel Old GC  -XX:+UseParallelOldGC):此类型的GC中年轻代和老年代GC都使用多线程进行。其它与并行GC相同,
  4. 并发标记清除收集器(Concurrent Mark Sweep (CMS) Collector) (-XX:+UseConcMarkSweepGC): CMS收集器是并发短暂停收集器。它为老年代进行垃圾回收。CMS收集器 经过与应用程序线程并发执行垃圾回收 从而缩短因GC而出现的暂停时间。CMS收集器在年轻代使用与并行收集器相同的算法。这类垃圾收集器适合不能容忍长时间暂停的响应程序。咱们能够经过JVM中的 -XX:ParallelCMSThreads=n 来设置CMS收集器中的线程数。
  5. G1 垃圾收集器G1 Garbage Collector (-XX:+UseG1GC) Java 7中可使用G1 垃圾收集器。它的最终目标是替换掉CMS收集器。G1收集器是一个并行、并发、增量压缩、低暂停的垃圾收集器。

      G1垃圾收集器不一样于其它收集器,它没有年轻代、老年代空间,它将堆空间划分红多个相同大小的堆区域(heap regions),当调用一次垃圾回收,它首先收集实时性不是很高的区域的数据,所以称为”Garbage First”。有关详细的可参考个人另一篇Blog:Java垃圾收集器之--Garbage-First Collector 

JAVA 垃圾收集监控

   咱们可使用Java命令行和UI工具来监控应用程序的垃圾收集活动。下面的例子中,我使用Java SE Downloads 中一个演示程序。

   若是你想使用一样的程序,前往 Java SE Downloads  页面下载JDK 7 and JavaFX Demos and Samples 我使用的和序示例是Java2Demo.jar  能够在jdk1.7.0_55/demo/jfc/Java2D 目录中找到。固然了这步可选。你能够选用任何Java程序执行GC监控命令。

  我使用的启动演示程序的命令是:

1
pankaj@Pankaj:~ /Downloads/jdk1 .7.0_55 /demo/jfc/Java2D $ java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar Java2Demo.jar

JSTAT

    咱们可使用 jstat 命令行工具来监控JVM内存和GC活动。标准的JDK中含有此命令。所以能够直接使用。

    运行 jstat 以前你须要知道程序的进程ID号。你能够运行 ps -eaf | grep java 命令来获取。

1
2
3
pankaj@Pankaj:~$ ps -eaf | grep Java2Demo.jar
501 9582  11579   0  9:48PM ttys000    0:21.66 /usr/bin/java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseG1GC -jar Java2Demo.jar
501 14073 14045   0  9:48PM ttys002    0:00.00 grep Java2Demo.jar

  个人Java程序的进程ID号为 9582.如今咱们能够以下执行jstat 命令。


1 pankaj@Pankaj:~$ jstat -gc 9582 1000
2  S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
3 1024.0 1024.0  0.0    0.0    8192.0   7933.3   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
4 1024.0 1024.0  0.0    0.0    8192.0   8026.5   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
5 1024.0 1024.0  0.0    0.0    8192.0   8030.0   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
6 1024.0 1024.0  0.0    0.0    8192.0   8122.2   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
7 1024.0 1024.0  0.0    0.0    8192.0   8171.2   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
8 1024.0 1024.0  48.7   0.0    8192.0   106.7    42108.0    23401.3   20480.0 19990.9    158    0.275  40      1.381    1.656
9 1024.0 1024.0  48.7   0.0    8192.0   145.8    42108.0    23401.3   20480.0 19990.9    158    0.275  40      1.381    1.656

 

      

jstat命令的最后一个参数是每次输出的时间间隔,所以它会每隔一秒打印内存及垃圾回收数据。下面详细看看每列。

    • S0C and S1C: 这列显示当前 Survivor0 and Survivor1 区域的大小(KB)
    • S0U and S1U: 这列显示 Survivor0 and Survivor1 区域的使用状况(KB). 其中一个Survivor区域老是空的
    • EC and EU: 这列显示Eden区的当前大小及使用状况(KB). 注意 EU 的大小逐渐增长,当达到EC大小, 最小化 GC 被调用 ,EU 的大小减少。
    • OC and OU: 这列显示了老年代的当前大小及使用状况(KB)
    • PC and PU: 这列显示了 持久化代(Perm Gen) 的当前大小及使用状况(KB)
    • YGC and YGCT: YGC 列显示年轻代发生GC事件的数量。 YGCT 列显示年轻代发生GC操做累计时间.  注意这两列值都在增长与EU值减小是在同一行。这主要是最小化GC的缘由。
    • FGC and FGCT: FGC 列显示了FUll GC发生的数量. FGCT 列显示了FULL GC操做的累计时间. 注意Full GC 所用的时间相比年轻代GC所用的时间要大的多
    • GCT:  这列显示了GC 操做总累计时间。 注意它是 YGCT 和 FGCT 值的总和

  jstat的优势在于它能够在无GUI的远程服务器上执行。注意S0C, S1C 和EC之和为 10M ,与咱们经过JVM选项 -Xmn10m 设置的值同样

Java VisualVM with Visual GC

    若是你想在GUI下查看内存及GC操做。 那么你可使用 jvisualvm 工具。Java VisualVM 也一样包含在JDK中,你不须要单独下载。

    只须要运行在终端上执行jvisualvm 命令来启动Java VisualVM程序。一旦启动,你须要经过Tools--》Plugins选项安装Visual GC 插件,正以下图所示。

       

   Visual GC 安装完毕后,左边列中打开程序前往Visual GC 部分。你将会获得以下图所示的JVM内存及GC截图。

   Java GC 调优是提升应用程序吞吐量的最后选择,只有当你发现长时间的GC致使性能降低而产生应用程序超时。

    你会在日志中看到java.lang.OutOfMemoryError: PermGen space的错误信息。而后能够尝试监控并经过使用JVM 选项  -XX:PermGen and -XX:MaxPermGen  来增长Perm Gen内存空间。你或许也能够尝试使用-XX:+CMSClassUnloadingEnabled 来检查使用CMS垃圾收集的性能如何?

   若是你发现大量的FUll GC操做,你能够试着增长老年代内存空间。

   总之GC调优须要花费大量的精力和时间,这里绝没有什么硬性或者快速的规则。你须要尝试不一样的选项,比较他们,并找对你应用程序来讲最好的那个。

   这就是全部有关Java内存模型和垃圾回收。我但愿这有助于你理解JVM内存模型及垃圾回收的过程。谢谢。

 

原文连接: JournalDev 翻译: TonySpark
译文连接: http://www.cnblogs.com/tonyspark/p/3731696.html

转载请保留原文出处、译者和译文连接。]

相关文章
相关标签/搜索