Java后台开发(2)——JVM参数设置和分析

前言

有时候程序会碰到java.lang.OutOfMemoryError,这个主要是JVM参数没有配好引发的。html

OutOfMemoryError分两种:java.lang.OutOfMemoryError: Java heap space和java.lang.OutOfMemoryError: PermGen space。java

前者是有关堆内存的内存溢出,能够经过配置-Xms和-Xmx参数来解决。web

后者是有关非堆内存的内存溢出,能够经过配置-XX:PermSize和-XX:MaxPermSize来设置。数组

参数的含义

打开eclipse的eclipse.ini会看到以下参数:缓存

-vmargsbash

-Xms128M服务器

-Xmx512Moracle

-XX:PermSize=64Meclipse

-XX:MaxPermSize=128Mjvm

-vmargs:用来讲明后面的就是JVM的参数了

-Xms:JVM初始分配的堆内存

-Xmx:JVM最大容许分配的堆内存,按需分配

-XX:PermSize:JVM初始分配的非堆内存

-XX:MaxPermSize:JVM最大容许分配的非堆内存,按需分配

堆(Heap)内存和非堆(Non-Heap)内存

堆内存

JVM留给开发者用的内存。通常存放对象以及数组。

JVM初始分配的堆内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的堆内存由-Xmx指定,默认是物理内存的1/4。

空余堆内存小于40%时,JVM就会增大堆内存直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减小堆内存直到-Xms的最小限制。所以服务器通常设置-Xms、-Xmx相等以免在每次GC后调整堆内存的大小。

若是-Xmx不指定或者指定偏小,应用可能会致使java.lang.OutOfMemory错误,此错误来自JVM,不是Throwable的,没法用try...catch捕捉。

非堆内存: 

JVM留给本身用的内存。方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每一个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。

JVM初始分配的非堆内存由-XX:PermSize指定,默认是物理内存的1/64;JVM最大分配的非堆内存由-XX:MaxPermSize 指定,默认是物理内存的1/4。(还有一说:MaxPermSize缺省值和-server -client选项相关,-server选项下默认MaxPermSize为64m,-client选项下默认MaxPermSize为32m)

-XX:MaxPermSize设置太小会致使java.lang.OutOfMemoryError: PermGen space,缘由以下:

PermGen space用于存放Class和Meta的信息,GC不会对PermGen space进行处理,因此若是Load不少Class的话,就会出现上述Error。这种Error在web服务器对JSP进行pre compile的时候比较常见

-server and -client

 

有两种类型的 HotSpot JVM,即”server”和”client”。服务端的VM中的默认为堆提供了一个更大的空间以及一个并行的垃圾收集器,而且在运行时能够更大程度地优 化代码。客户端的VM更加保守一些(校对注:这里做者指客户端虚拟机有较小的默认堆大小),这样能够缩短JVM的启动时间和占用更少的内存。有一个 叫”JVM功效学”的概念,它会在JVM启动的时候根据可用的硬件和操做系统来自动的选择JVM的类型。具体的标准能够在这里找到。从标准表中,咱们能够看到客户端的VM只在32位系统中可用。

 

若是咱们不喜欢预选(校对注:指JVM自动选择的JVM类型)的JVM,咱们可使 用-server和-client参数来设置使用服务端或客户端的VM。虽然当初服务端VM的目标是长时间运行的服务进程,可是如今看来,在运行独立应用 程序时它比客户端VM有更出色的性能。当应用的性能很是重要时,我推荐使用-server参数来选择服务端VM。一个常见的问题:在一个32位的系统 上,HotSpot JDK能够运行服务端VM,可是32位的JRE只能运行客户端VM。

 

-version and -showversion

 

当咱们调用“java”命令时,咱们如何才能知道咱们安装的是哪一个版本的Java和JVM类型呢?在同一个系统中安装多个Java,若是不注意的话有运行错误JVM的风险。在不一样的Linux版本上预装JVM这方面,我认可如今已经变的比之前好不少了。幸运的是,咱们如今可使用-version参数,它能够打印出正在使用的JVM的信息。例如:

 

$ java -version
java version "1.6.0_24" Java(TM) SE Runtime Environment (build 1.6.0_24-b07) Java HotSpot(TM) Client VM (build 19.1-b02, mixed mode, sharing)

 

 

输出显示的是Java版本号(1.6.0_24)和JRE确切的build号(1.6.0_24-b07)。咱们也能够看到JVM的名字(HotSpot)、类型(client)和build ID(19.1-b02) )。 除此以外,咱们还知道JVM以混合模式(mixed mode)在运行,这是HotSpot默认的运行模式,意味着JVM在运行时能够动态的把字节码编译为本地代码。咱们也能够看到类数据共享(class data sharing)是开启的,类数据共享(class data sharing)是一种在只读缓存(在jsa文件中,”Java Shared Archive”)中存储JRE的系统类,被全部Java进程的类加载器用来当作共享资源。类数据共享(Class data sharing)可能在常常从jar文档中读全部的类数据的状况下显示出性能优点。

-version参数在打印完上述信息后当即终止JVM。还有一个相似的参数 -showversion能够用来输出相同的信息,可是-showversion紧接着会处理并执行Java程序。所以,-showversion对几乎 全部Java应用的命令行都是一个有效的补充。你永远不知道你何时,忽然须要了解一个特定的Java应用(崩溃时)使用的JVM的一些信息。在启动时添加-showversion,咱们就能保证当咱们须要时能够获得这些信息。

 

-Xint, -Xcomp, 和 -Xmixed

 

-Xint和-Xcomp参数和咱们的平常工做不是很相关,可是我很是有兴趣经过它来了解下JVM。在解释模式(interpreted mode)下,-Xint标记会强制JVM执行全部的字节码,固然这会下降运行速度一般低10倍或更多。- Xcomp参数与它(-Xint)正好相反,JVM在第一次使用时会把全部的字节码编译成本地代码,从而带来最大程度的优化。这听起来不错,由于这彻底绕 开了缓慢的解释器。然而,不少应用在使用-Xcomp也会有一些性能损失,固然这比使用-Xint损失的少,缘由是-xcomp没有让JVM启用JIT编 译器的所有功能。JIT编译器在运行时建立方法使用文件,而后一步一步的优化每个方法,有时候会主动的优化应用的行为。这些优化技术,好比,积极的分支 预测(optimistic branch prediction),若是不先分析应用就不能有效的使用。另外一方面方法只有证实它们与此相关时才会被编译,也就是,在应用中构建某种热点。被调用不多 (甚至只有一次)的方法在解释模式下会继续执行,从而减小编译和优化成本。

 

注意混合模式也有他本身的参数,-Xmixed。最新版本的HotSpot的默认模式是混合模式,因此咱们不须要特别指定这个标记。咱们来用对象填充HashMap而后检索它的结果作一个简单的用例。每个例子,它的运行时间都是不少次运行的平均时间。

$ java -server -showversion Benchmark java version "1.6.0_24" Java(TM) SE Runtime Environment (build 1.6.0_24-b07) Java HotSpot(TM) Server VM (build 19.1-b02, mixed mode)   Average time: 0.856449 seconds

 

$ java -server -showversion -Xcomp Benchmark java version "1.6.0_24" Java(TM) SE Runtime Environment (build 1.6.0_24-b07) Java HotSpot(TM) Server VM (build 19.1-b02, compiled mode)   Average time: 0.950892 seconds

  $ java -server -showversion -Xint Benchmark java version "1.6.0_24" Java(TM) SE Runtime Environment (build 1.6.0_24-b07) Java HotSpot(TM) Server VM (build 19.1-b02, interpreted mode)   Average time: 7.622285 seconds

  固然也有不少使-Xcomp表现很好的例子。特别是运行时间长的应用,我强烈建议你们使用JVM的默认设置,让JIT编译器充分发挥其动态潜力,毕竟JIT编译器是组成JVM最重要的组件之一。事实上,正是由于JVM在这方面的进展才让Java再也不那么慢。

参考连接:

  1. JVM启动参数设置:http://blog.csdn.net/tianjf0514/article/details/20793523
  2. Non-standard JVM HotSpot VM Option:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
  3. Standard JVM HotSpot VM Option:http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/java.html
  4. JVM类型及编译器模式:http://ifeve.com/useful-jvm-flags-part-1-jvm-types-and-compiler-modes-2/
  5. JVM内存调优:http://ifeve.com/useful-jvm-flags-part-4-heap-tuning/
相关文章
相关标签/搜索