`
hlbng
  • 浏览: 178027 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JVM调优

阅读更多

1. Heap设定与垃圾回收

       Java Heap分为3个区,Young,Old和Permanent。Young保存刚实例化的对象。当该区被填满时,GC会将对象移到Old区。Permanent区则负责保存反射对象,本文不讨论该区。

       JVM的Heap分配可以使用-X参数设定,

       -Xms 初始Heap大小

       -Xmx java heap最大值

       -Xmn young generation的heap大小 

       JVM有2个GC线程。第一个线程负责回收Heap的Young区。第二个线程在Heap不足时,遍历Heap,将Young 区升级为Older区。Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能。

       为什么一些程序频繁发生GC?有如下原因:

       1)程序内调用了System.gc()或Runtime.gc()。

       2)一些中间件软件调用自己的GC方法,此时需要设置参数禁止这些GC。

       3)Java的Heap太小,一般默认的Heap值都很小。

       4)频繁实例化对象,Release对象。此时尽量保存并重用对象,例如使用StringBuffer()和String()。

       如果你发现每次GC后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态。许多Server端的Java程序每次GC后最好能有65%的剩余空间。

       经验之谈:

       1)Server端JVM最好将-Xms和-Xmx设为相同值。为了优化GC,最好让-Xmn值约等于-Xmx的1/3[2]。

       2)一个GUI程序最好是每10到20秒间运行一次GC,每次在半秒之内完成[2]。


       注意:

       1)增加Heap的大小虽然会降低GC的频率,但也增加了每次GC的时间。并且GC运行时,所有的用户线程将暂停,也 就是GC期间,Java应用程序不做任何工作。

       2)Heap大小并不决定进程的内存使用量。进程的内存使用量要大于-Xmx定义的值,因为Java为其他任务分配内存,例如每个线程的Stack等。


2.Stack的设定

       每个线程都有他自己的Stack。

       -Xss 每个线程的Stack大小 

       Stack的大小限制着线程的数量。如果Stack过大就好导致内存溢漏。-Xss参数决定Stack大小,例如-Xss1024K。如果Stack太小,也会导致Stack溢漏。

3.硬件环境

       硬件环境也影响GC的效率,例如机器的种类,内存,swap空间,和CPU的数量。

       如果你的程序需要频繁创建很多transient对象,会导致JVM频繁GC。这种情况你可以增加机器的内存,来减少Swap空间的使用[2]。

4.4种GC

       第一种为单线程GC,也是默认的GC。,该GC适用于单CPU机器。

       第二种为Throughput GC,是多线程的GC,适用于多CPU,使用大量线程的程序。第二种GC与第一种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程。-XX:+UseParallelGC参数启动该GC。

       第三种为Concurrent Low Pause GC,类似于第一种,适用于多CPU,并要求缩短因GC造成程序停滞的时间。这种GC可以在Old区的回收同时,运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC。

       第四种为Incremental Low Pause GC,适用于要求缩短因GC造成程序停滞的时间。这种GC可以在Young区回收的同时,回收一部分Old区对象。-Xincgc参数启动该GC。


最后附上用java -X 命令查看JVM的配置说明:

D:\j2sdk15\bin>java -X

    -Xmixed           mixed mode execution (default)

    -Xint             interpreted mode execution only

    -Xbootclasspath:<directories and zip/jar files separated by ;>

                      set search path for bootstrap classes and resources

    -Xbootclasspath/a:<directories and zip/jar files separated by ;>

                      append to end of bootstrap class path

    -Xbootclasspath/p:<directories and zip/jar files separated by ;>

                      prepend in front of bootstrap class path

    -Xnoclassgc       disable class garbage collection

    -Xincgc           enable incremental garbage collection

    -Xloggc:<file>    log GC status to a file with time stamps

    -Xbatch           disable background compilation

    -Xms<size>        set initial Java heap size

    -Xmx<size>        set maximum Java heap size

    -Xss<size>        set java thread stack size

    -Xprof            output cpu profiling data

    -Xfuture          enable strictest checks, anticipating future default

    -Xrs              reduce use of OS signals by Java/VM (see documentation)

    -Xcheck:jni       perform additional checks for JNI functions

    -Xshare:off       do not attempt to use shared class data

    -Xshare:auto      use shared class data if possible (default)

    -Xshare:on        require using shared class data, otherwise fail.

 

The -X options are non-standard and subject to change without notice.

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

 

JVM配置参数中文说明:

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

1、-Xmixed           mixed mode execution (default)

 混合模式执行 

2、-Xint             interpreted mode execution only

 解释模式执行 

3、-Xbootclasspath:<directories and zip/jar files separated by ;>

      set search path for bootstrap classes and resources

 设置zip/jar资源或者类(.class文件)存放目录路径 

3、-Xbootclasspath/a:<directories and zip/jar files separated by ;>

      append to end of bootstrap class path

 追加zip/jar资源或者类(.class文件)存放目录路径 

4、-Xbootclasspath/p:<directories and zip/jar files separated by ;>

      prepend in front of bootstrap class path

 预先加载zip/jar资源或者类(.class文件)存放目录路径 

5、-Xnoclassgc       disable class garbage collection

 关闭类垃圾回收功能 

6、-Xincgc           enable incremental garbage collection

 开启类的垃圾回收功能 

7、-Xloggc:<file>    log GC status to a file with time stamps

 记录垃圾回日志到一个文件。 

8、-Xbatch           disable background compilation

 关闭后台编译 

9、-Xms<size>        set initial Java heap size

 设置JVM初始化堆内存大小 

10、-Xmx<size>        set maximum Java heap size

 设置JVM最大的堆内存大小 

11、-Xss<size>        set java thread stack size

 设置JVM栈内存大小 

12、-Xprof            output cpu profiling data

 输入CPU概要表数据 

13、-Xfuture          enable strictest checks, anticipating future default

 执行严格的代码检查,预测可能出现的情况 

14、-Xrs              reduce use of OS signals by Java/VM (see documentation)

 通过JVM还原操作系统信号 

15、-Xcheck:jni       perform additional checks for JNI functions

 对JNI函数执行检查 

16、-Xshare:off       do not attempt to use shared class data

 尽可能不去使用共享类的数据 

17、-Xshare:auto      use shared class data if possible (default)

 尽可能的使用共享类的数据

18、-Xshare:on       require using shared class data, otherwise fail.

 尽可能的使用共享类的数据,否则运行失败
 

The -X options are non-standard and subject to change without notice.

 

 

      调整JVM GC(Garbage Collection),可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率。但是调整GC是以个极为复杂的过程,

由于各个程序具备不同的特点,如:web和GUI程序就有很大区别(Web可以适当的停顿,但GUI停顿是客户无法接受的),而且由于跑在各个机器上的配置不同(主要cup个数,内存不同),

所以使用的GC种类也会不同。接下来,我简单介绍一下如何调整GC。

     首先说一下如何监视GC,你可以使用我以前文章中提到的JDK中的jstat工具 ,也可以在java程序启动的opt里加上如下几个参数(注:这两个参数只针对SUN的HotSpot VM):

    -XX:-PrintGC     Print messages at garbage collection. Manageable.

    -XX:-PrintGC Details     Print more details at garbage collection. Manageable. (Introduced in 1.4.0.)

    -XX:-PrintGCTimeStamps     Print timestamps at garbage collection. Manageable (Introduced in 1.4.0.)


   当把-XX:-PrintGC Details 加入到java opt里以后可以看见如下输出:

    [GC [DefNew: 34538K->2311K(36352K), 0.0232439 secs] 45898K->15874K(520320K), 0.0233874 secs]

    [Full GC [Tenured: 13563K->15402K(483968K), 0.2368177 secs] 21163K->15402K(520320K), [Perm : 28671K->28635K(28672K)], 0.2371537 secs]



    他们分别显示了GC的过程,清理出了多少空间。第一行GC使用的是 ‘普通GC’(Minor Collections),第二行使用的是 ‘全GC’(Major Collections)。他们的区别很大,在第一行最后

我们可以看见他的时间是0.0233874秒,而第二行的Full GC的时间是0.2371537秒。第二行的时间是第一行的接近10倍,也就是我们这次调优的重点,减少Full GC 的次数,因为Full GC

会暂停程序比较长的时间,如果Full GC 的次数比较多。程序就会经常性的假死。当然这只是他们的表面现象,接下来我仔细介绍一下GC,和 Full GC(为后面的调优做准备)。



      我们知道Java和C++的区别主要是,Java不需要像c++那样,由程序员主动的释放内存。而是由JVM里的GC(Garbage Collection)来,在适当的时候替我们释放内存。GC 的内部工作,

即GC的算法有很多种, 如:标记清除收集器,压缩收集器,分代收集器等等。现在比较常用的是分代收集(也是SUN VM使用的),即将内存分为几个区域,将不同生命周期的对象放在不同区域里

(新的对象会先 生成在Young area,在几次GC以后,如过没有收集到,就会逐渐升级到Tenured area)。在GC收集的时候,频繁收集生命周期短的区域(Young area),因为这个区域内的

对象生命周期比较短,GC 效率也会比较高。而比较少的收集生命周期比较长的区域(Old area or Tenured area),以及基本不收集的永久区(Perm area)。



     注:Young area又分为三个区域分别叫Eden,和俩个Survivor spaces。Eden用来存放新的对象,Survivor spaces用于 新对象 升级到 Tenured area时的 拷贝。

     我们管收集 生命周期短的区域(Young area) 的收集叫 GC,而管收集 生命周期比较长的区域(Old area or Tenured area)的收集叫 Full GC,因为他们的收集算法不同,

所以使用的时间也会不同。我们要尽量减少 Full GC 的次数。



      接下来介绍一下 HotSpot VM GC 的种类,GC在 HotSpot VM 5.0里有四种。一种是默认的叫 serial collector,另外几种分别叫throughput collector,concurrent 

low pause collector, incremental (sometimes called train) low pause collector(废弃掉了)。以下是SUN的官方说明:  



   1. The throughput collector: this collector uses a parallel version of the young generation collector. It is used if the 

-XX:+UseParallelGC option is passed on the command line. The tenured generation collector is the same as the serial collector.

   2. The concurrent low pause collector: this collector is used if the -Xincgc&#8482; or -XX:+UseConcMarkSweepGC is passed on the command line.

 The concurrent collector is used to collect the tenured generation and does most of the collection concurrently with the execution of 

the application. The application is paused for short periods during the collection. A parallel version of the young generation copying

 collector is used with the concurrent collector. The concurrent low pause collector is used if the option -XX:+UseConcMarkSweepGC is

 passed on the command line.

   3. The incremental (sometimes called train) low pause collector: this collector is used only if -XX:+UseTrainGC is passed on the 

command line. This collector has not changed since the J2SE Platform version 1.4.2 and is currently not under active development. 

It will not be supported in future releases. Please see the 1.4.2 GC Tuning Document for information on this collector.



       简单来说就是throughput collector和concurrent low pause collector:使用多线程的方式,利用多CUP来提高GC的效率,而throughput collector与concurrent 

low pause collector的去别是throughput collector只在young area使用使用多线程,而concurrent low pause collector则在tenured generation也使用多线程。



        根据官方文档,他们俩个需要在多CPU的情况下,才能发挥作用。在一个CPU的情况下,会不如默认的serial collector,因为线程管理需要耗费CPU资源。而在两个CPU的情况下,

也挺高不大。只是在更多CPU的情况下,才会有所提高。当然 concurrent low pause collector有一种模式可以在CPU较少的机器上,提供尽可能少的停顿的模式,见下文。



        当要使用throughput collector时,在java opt里加上-XX:+UseParallelGC,启动throughput collector收集。也可加上-XX:ParallelGCThreads=<desired number>来改变线程数。

还有两个参数 -XX:MaxGCPauseMillis=<nnn>和 -XX:GCTimeRatio=<nnn>,MaxGCPauseMillis=<nnn>用来控制最大暂停时间,而-XX: GCTimeRatio可以提高GC说占CPU的比,

以最大话的减小heap。



      当要使用 concurrent low pause collector时,在java的opt里加上 -XX:+UseConcMarkSweepGC。concurrent low pause collector还有一种为CPU少的机器

准备的模式,叫Incremental mode。这种模式使用一个CPU来在程序运行的过程中GC,只用很少的时间暂停程序,检查对象存活。



        在Incremental mode里,每个收集过程中,会暂停两次,第二次略长。第一次用来,简单从root查询存活对象。第二次用来,详细检查存活对象。整个过程如下:  



    * stop all application threads; do the initial mark; resume all application threads(第一次暂停,初始话标记)

    * do the concurrent mark (uses one procesor for the concurrent work)(运行是标记)

    * do the concurrent pre-clean (uses one processor for the concurrent work)(准备清理)

    * stop all application threads; do the remark; resume all application threads(第二次暂停,标记,检查)

    * do the concurrent sweep (uses one processor for the concurrent work)(运行过程中清理)

    * do the concurrent reset (uses one processor for the concurrent work)(复原)



       当要使用Incremental mode时,需要使用以下几个变量:

       -XX:+CMSIncrementalMode default: disabled 启动i-CMS模式(must with -



XX:+UseConcMarkSweepGC)

       -XX:+CMSIncrementalPacing default: disabled 提供自动校正功能

       -XX:CMSIncrementalDutyCycle=<N> default: 50 启动CMS的上线

       -XX:CMSIncrementalDutyCycleMin=<N> default: 10 启动CMS的下线

       -XX:CMSIncrementalSafetyFactor=<N> default: 10 用来计算循环次数

       -XX:CMSIncrementalOffset=<N> default: 0 最小循环次数(This is the percentage (0-



100) by which the incremental mode duty cycle is shifted to the right within the period



between minor collections.)

       -XX:CMSExpAvgFactor=<N> default: 25 提供一个指导收集数



      SUN推荐的使用参数是:



        -XX:+UseConcMarkSweepGC \

        -XX:+CMSIncrementalMode \

        -XX:+CMSIncrementalPacing \

        -XX:CMSIncrementalDutyCycleMin=0 \

        -XX:CMSIncrementalDutyCycle=10 \

        -XX:+PrintGC Details \

        -XX:+PrintGCTimeStamps \

        -XX:-TraceClassUnloading



       注:如果使用throughput collector和concurrent low pause collector,这两种垃圾收集器,需要适当的挺高内存大小,以为多线程做准备。

分享到:
评论
1 楼 hlbng 2009-05-12  
分析java.lang.OutOfMemoryError: PermGen space

发现很多人把问题归因于: spring,hibernate,tomcat,因为他们动态产生类,导致JVM中的permanent heap溢出 。然后解决方法众说纷纭,有人说升级 tomcat版本到最新甚至干脆不用tomcat。还有人怀疑spring的问题,在spring论坛上讨论很激烈,因为spring在AOP时使用CBLIB会动态产生很多类。

但问题是为什么这些王牌的开源会出现同一个问题呢,那么是不是更基础的原因呢?tomcat在Q&A很隐晦的回答了这一点,我们知道这个问题,但这个问题是由一个更基础的问题产生。

于是有人对更基础的JVM做了检查,发现了问题的关键。原来SUN 的JVM把内存分了不同的区,其中一个就是permenter区用来存放用得非常多的类和类描述。本来SUN设计的时候认为这个区域在JVM启动的时候就固定了,但他没有想到现在动态会用得这么广泛。而且这个区域有特殊的垃圾收回机制,现在的问题是动态加载类到这个区域后,gc根本没办法回收!


对于以上两个问题,我的处理是:

在catalina.bat(windows)中代码
“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:
set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m   
set JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m 


在catalina.sh(linux)中代码
“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:
JAVA_OPTS=-Xms64m -Xmx256m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m  

相关推荐

    JVM调优实践 ⼀、JVM调优准备⼯作 实验报告 pdf

    在JVM调优实践中,了解各个运行时数据区的工作原理至关重要。以下是对这些区域的详细解析: 1. **虚拟机栈**:每个线程都有一个独立的虚拟机栈,用于存储方法调用时的栈帧。栈帧中包含局部变量表(存储方法中的变量...

    马士兵jvm调优笔记.docx

    ### 马士兵JVM调优笔记知识点梳理 #### 一、Java内存结构 Java程序运行时,其内存被划分为几个不同的区域,包括堆内存(Heap)、方法区(Method Area)、栈(Stack)、程序计数器(Program Counter Register)以及...

    JVM调优总结.pdf

    JVM调优是一个复杂的过程,它涉及到对Java虚拟机内部工作原理的深刻理解。本文档总结了JVM调优的基础知识和一些核心概念,旨在帮助开发者更好地掌握Java程序的性能优化。 首先,文档提到了Java中的数据类型分为基本...

    monkey老师的jvm 调优

    《Monkey老师的JVM调优深度解析》 在Java开发领域,JVM(Java Virtual Machine)是每一个程序员都需要深入了解的关键组成部分。Monkey老师的JVM调优课程,无疑为我们提供了一个宝贵的平台,来深入探究JVM的工作原理...

    JVM调优工具命令详解.pdf

    在现代的软件开发与运行环境中,Java虚拟机(JVM)的性能调优是非常重要的一环,特别是在处理大型应用程序或者服务时,合适的JVM调优能够显著提升系统性能和稳定性。本篇文档详细介绍了JVM调优工具的命令使用及其...

    JVM调优篇.pdf

    JVM类加载机制详解 JVM类加载机制是Java虚拟机中的一种机制,它负责加载Java类文件到内存中,以便执行Java程序。类加载机制分为五个阶段:加载、验证、准备、解析和初始化。 加载 加载是类加载过程中的一个阶段,...

    JVM调优攻略.pdf

    ### JVM调优攻略 #### 一、概述 《JVM调优攻略》是一份详尽的文档,旨在帮助开发者理解并掌握Java虚拟机(JVM)的优化技巧。本指南不仅适用于初学者,对于有一定基础的开发人员来说也同样具有很高的参考价值。文档中...

    JVM调优技巧

    JVM深入理解,JVM调优技巧

    推荐一些JVM原理,JVM调优,JVM内存模型,JAVA并发 电子书1

    标题中提到了JVM原理、JVM调优、JVM内存模型和JAVA并发,这些都是Java虚拟机(JVM)相关的核心概念。JVM是运行Java字节码的虚拟计算机,为Java提供了一个跨平台的环境,确保Java程序可以在不同的操作系统上运行而...

    系统和JVM调优(面试突击)

    系统和JVM调优是Java开发人员在面试中经常遇到的话题,这关乎程序性能优化、内存管理和稳定性。本文将深入探讨这两个关键领域的核心概念,并提供一些实战策略。 首先,我们来了解一下系统调优。系统调优主要包括...

    JVM调优.pdf

    ### JVM调优详解 #### 一、JVM调优概述 在现代软件开发中,Java虚拟机(JVM)作为Java应用程序的运行环境,对于提高应用程序的性能至关重要。JVM调优是指通过调整JVM的各种参数来优化Java应用程序的运行效率,减少...

    JVM面试资料:JVM结构、JVM调优、四大垃圾回收算法、七大垃圾回收器

    JVM面试资料。 JVM结构:类加载器,执行引擎,本地方法接口,本地内存结构; 四大垃圾回收算法:复制算法、标记-清除算法、标记-整理算法、分代收集算法 ...JVM调优:命令行指令,设置堆内存大小的参数

    java高级篇:JVM调优.mp4

    分析常见的JVM调优技术及其相关条件,以及在实战中怎么使用到相关的技术进行调优,比较适合中高级开发进行学习,适合对JVM理解较深的开发学习

    JVM调优详解.docx

    JVM 调优详解 JVM 调优是 Java 虚拟机(Java Virtual Machine)中的一种技术,用于优化 Java 应用程序的性能和内存使用。其中,垃圾回收(Garbage Collection)是 JVM 调优的重要组成部分,本文将详细介绍 JVM 调优...

    马老师jvm调优实战笔记

    马老师 JVM 调优实战笔记 JVM 调优是 Java 开发者们不可或缺的技能,它直接影响着 Java 应用程序的性能和稳定性。本笔记是马老师的 JVM 调优实战笔记,涵盖了 JVM 的概述、内存结构、堆内存、垃圾回收算法、JVM ...

    jvm调优视频

    深入jvm内核--原理,诊断与优化的优秀视频,需要深入jvm的同学可以下载来看一看

    JVM调优实战.doc

    《JVM调优实战》是一份深入探讨Java虚拟机(JVM)性能优化的文档,主要分为理论篇和实战篇两大部分。本文将详细解析其中的关键知识点。 理论篇首先介绍了JVM内存模型,将其比喻为一个多功能的养鱼塘。在这个比喻中...

    eclipse jvm调优

    对于使用eclipse卡或者在启动项目,空间分配不足导致慢等问题。

    JVM调优工具Jprofiler内存泄漏定位的简单分析(附源码)(二)

    在Java开发过程中,性能优化是不可或缺的一环,而JVM调优则是其中的关键步骤。本文将深入探讨如何利用专业工具JProfiler进行内存泄漏的定位,帮助开发者找出并解决潜在问题,提升应用程序的运行效率。我们将结合附带...

    Jvm调优和SpringBoot项目优化的详细教程

    JVM调优和SpringBoot项目优化是提升应用性能和稳定性的关键环节。首先,我们要了解JVM(Java Virtual Machine)调优的基本概念。JVM作为Java应用程序的运行环境,其性能直接影响程序的运行效率。调优主要包括调整堆...

Global site tag (gtag.js) - Google Analytics