9 JVM内存参数调优
我们前面所提到的堆内存(heap)是由Java虚拟机控制管理的,因此,这些参数对JVM而言都有一个默认值,但在某些情况下这些参数的默认值并不是最优的,这就需要我们通过调整这些参数的值来提高JVM的性能,最终提高应用的性能指标。
在实际的应用开发中,如果应用所使用的系统内存较大,经常会引发内存溢出的错误:
… java.lang.OutOfMemoryError <<no stack trace available>> java.lang.OutOfMemoryError <<no stack trace available>> Exception in thread "main" …
这可能是因为应用要使用的堆内存(heap)超过了JVM所管理内存范围,如果我们适当追加内存值有时就可以避免这种致命错误的出现。
在WINDOWS系统上你可以通过参数-verbosegc查看JVM回收内存的信息,在HP UNIX系统上你可以通过-Xverbosegc:file=/tmp/gc$$.out参数将信息重定向到一个文件中。然后查看相应的信息,例如下面的这个类。
public class A { public static void main(String args[]) { for (int i =0 ;i < 100000;++i) { A a = new A(); } System.out.println("this is a GC test"); } }
在类A的main方法中创建了100 000个A对象,然后我们看一下JVM回收内存的情况,编译并执行这个类:
>java -verbosegc A
[GC 512K->91K(1984K), 0.0027537 secs]
this is a GC test
从输出信息中可以看出总共有1984KB的内存被回收,耗时0.002 753 7秒。现在我们将类A添加一行清除对象引用的代码:
public class A { public static void main(String args[]) { for (int i =0 ;i < 100000;++i) { A a = new A(); a = null; } System.out.println("this is a GC test"); } }
编译并执行这个类:
>java -verbosegc A
[GC 512K->91K(1 984K), 0.0 027 450 secs]
this is a GC test
我们看到被回收内存的数量并没有变化,
但是回收所需要的时间却变成了0.002 745 0秒,后者比前者节省了0.000 008 7秒,千万不要小看这0.000 008
7秒,当你的应用足够复杂时这个时间就会成指数级增长,看来我们主动清除对象引用的方法,确实可以加速JVM对垃圾内存的回收。
如果再在类A中加入一行强制系统内存回收的代码,结果又会怎样呢?如下所示:
public class A { public static void main(String args[]) { for (int i =0 ;i < 100000;++i) { A a = new A(); a = null; } System.gc(); System.out.println("this is a GC test"); } }
编译并执行这个类:
>java -verbosegc A
[GC 512K->91K(1984K), 0.0 027 272 secs]
[Full GC 487K->91K(1984K), 0.0 070 730 secs]
this is a GC test
系统这次做了两次内存回收,第一次是程
序中强制系统内存回收的代码System.gc()导致的内存回收,而后者是系统最终的内存回收操作,我们看到强制内存回收耗时不长,可是却导致了系统最
终垃圾回收的时间加长了很多,因此我们在采用强制系统垃圾回收(通过显式调用方法System.gc())的办法来回收系统垃圾内存的办法,还是存在一些
弊端的,应尽量少用,或者说只在必要的时候应用。
上面我们提到的内存回收操作就是回收JVM所管理的堆内存(heap)。当系统
连续申请内存并且超过JVM所管理的堆内存(heap)的最大值时,就会产生系统内存溢出的致命异常,下面我们来看一下怎样通过设置JVM的内存参数来优
化JVM对内存的管理,避免内存溢出异常的发生。下表所示的就是与JVM内存相关的参数及其说明。
JVM
堆内存
(
heap
)
设置选项
|
参数格式 |
说明
|
设置新对象生产堆内存(Setting the Newgeneration heap size)
|
-XX:NewSize |
通
过这个选项可以设置
java
新对象生产堆内存
。在通常情况下这个选项的数值为
1024的整
数倍并且大于1MB
。这个值的取值规则为,一般情况下这个值-XX:NewSize
是最大堆内存(maximum heap size)
的四分之一。增加这个选项值的大小是为了增大较大数量的短生命周期对象
增加Java新对
象生产堆内存相当于增加了处理器的数目
。并且可以并行地分配内存,但是请注意内存的垃圾回收却是不可以并行处理的
|
设置最大新对象生产堆内存(Setting the maximum New generation heap size)
|
-XX:MaxNewSize |
通过这个选项可以设置最大Java
新对象生产堆内存
。通常情况下这个选项的数值为1024
的
整数倍并且大于1MB
其功用与上面的设置新对象生产堆内存-XX:NewSize
相同
|
设置新对象生产堆内存的比例(Setting New heap size ratios)
|
-XX:SurvivorRatio |
新对象生产区域通
常情况下被分为3
个子区域:伊甸园,与两个残存对象空间,
这两个空间的大小是相同的
。通过用-XX:SurvivorRatio=X
选项配置伊甸园与残存对象空间(Eden/survivor)
的大小的比例。
你可以试着将这个值设置为8
,然后监控、观察垃圾回收的工作情况
|
设置堆内存池的最小值(Setting minimum heap size)
|
-Xms |
通过这个选项可以要求系统为堆内存池分配内存空间的最小值
。通常情况下这个选项的数值为1024的整数倍并且大于1MB
。这个值的取值规则为,一般情况下这个值(-Xms)
与最大堆内存相同,以降低垃圾回收的频度
|
设置堆内存池的最大值
(Setting maximum heap size)
|
-Xmx |
通过这个选项可以要求系统为堆内存池分配内存空间的最大值
。通常情况下这个选项的数值为1024
的整数倍并且大于1MB。
一般情况下这个值
(-Xmx)与最小堆内存(minimum heap size -Xms)
相同,以降低垃圾回收的频度
|
取消垃圾回收 | -Xnoclassgc | 这个选项用来取消系统对特定类的垃圾回收。它可以防止当这个类的所有引用丢失之后,这个类仍被引用时不会再一次被重新装载,因此这个选项将增大系统堆内存的空间 |
设置栈内存的大小 | -Xss |
这个选项用来控制本地线程栈的大小
,当这个选项被设置的较大(>2MB)
时将会在很大程度上降低系统的性能
。因此在设置这个值时应该格外小心,调整后要注意观察系统的性能,不断调整以期达到最优
|
根据上表中所描述的参数意义,我们可以在启动应用时为JVM设置相应的参数值以提高系统的性能,如下所示:
java -XX:NewSize=128m -XX:MaxNewSize=128m -XX:SurvivorRatio=8 -Xms512m
-Xmx512m MyApplication
类文件(.class)的大小
由Java源文件.java文件编译成JVM可解释执行的Java字节文
件.class。因所采用的编译方式的不同而大小也不同。通常.class文件的大小也存在是否占用较大内存的问题。通过降低.class文件的大小,不但可以降低系统内存的开销,而且还可以节省网络开销,虽然这部分内容与JVM内存管理联系不大,但是我觉得还是有必要提一下,因为这在你开发Applet应用
时会有帮助。因为一般来说,Applet应用都是靠网络分布式传输
由客户端浏览器装载运行的,如果类文件较大,无疑将会增大网络开销,降低传输速度无法满足用户的需求,并且如果类文件较大,无疑也会消耗客户端内存资源。
我们可以通过在Java编译器javac中添加相应的参数,来缩小类文件的大小,解决上面的问题。
通常有三种编译方式会影响类文件的大小。
(1)默认编译方式: javac A.java。
(2)调试编译方式: javac –g A.java。
(3)代码编译方式: javac –g:none A.java。
例如如下所示的简单的类A:
public class A { public static void main(String args[]) { for (int i =0 ;i < 100000;++i) { A a = new A(); } } }
通过上面这三种方式编译后的类文件的大小分别为:
默认编译方式:291字节。
调试编译方式:422字节。
代码编译方式:207字节。
采用三种不同的方式,编译产生的类文件的大小差异非常大,这是什么原因导致的呢?原来在于.class文件中包含多个不同的部分或属性。
代码(Code)属性包含实际的方法字节码。源文件信息(SourceFile
Information)包含用于生成.class的源文件名称。代码行序号表(LineNumberTable)用来映射源文件中的代码行序号与字节码
文件中的序号偏移。本地变量表(LocalVariableTable)用来映射本地变量与栈桢的偏移。
注意
如果你想了解字节码文件.class的文件结构详细信息,请参考相关的技术资料,这里就不详细讲解了。
正是由于上面这三种编译方式生成的类文件所包含的信息不同,才导致了类文件的大小差异较大,其包含的信息分别如下所示。
默认编译方式:
代码(Code)、源文件信息(SourceFile Information)、代码行序号表(LineNumberTable)。
调试编译方式:
代码(Code)、源文件信息(SourceFile Information)、代码行序号表(LineNumberTable)、本地变量表(LocalVariableTable)。
代码编译方式:
代码(Code)。
这就是三种编译方式产生类文件大小不同的根本原因。而这三种编译方式在程序开发的不同阶段却都起着非常重要的作用,例如,调试编译方式在程序的调试开发过程中应采用,以获取更为详细的调试信息。因此具体应用上面的三种编译方式中的哪一种,应该适时而定。
发表评论
-
【JAVA优化编程】表达式、语句与保留字之——(4)正则表达式
2011-03-12 20:46 04 正则表达式 正则表达式对于熟悉脚本语言 ... -
【JAVA优化编程】表达式、语句与保留字之——(3)判断语句与循环语句
2011-03-12 19:32 19733 判断语句与循环语句 ... -
【JAVA优化编程】表达式、语句与保留字之——(2)Java语言中的保留字
2011-03-08 23:02 9302 Java语言中的保留字 任何一种语言都 ... -
【JAVA优化编程】表达式、语句与保留字之——(1)表达式
2011-03-05 11:52 775表达式与语句是任何程序设计语言的基础,也是开发大型软件 ... -
【JAVA优化编程】内存管理之——(10)Java程序设计中有关内存管理的其他经验
2011-02-18 17:36 109710 Java程序设计中有关 ... -
【JAVA优化编程】内存管理之——(8)不要提前创建对象
2011-02-13 16:54 9568 不要提前创建对象 尽量在需要的时候创建 ... -
【JAVA优化编程】内存管理之——(7)瞬间值
2011-02-13 16:41 9647 瞬间值 相信你在做远程方法调用 ... -
【JAVA优化编程】内存管理之——(6)对象重用与GC
2011-02-13 16:08 13646 对象重用与GC 有时候我们为了提高系统 ... -
【JAVA优化编程】内存管理之——(5)共享静态变量存储空间
2011-02-11 13:29 13275 共享静态变量存储空间 我们知道类中的静 ... -
【JAVA优化编程】内存管理之——(4)数组的创建
2011-02-11 11:35 8134 数组的创建 ... -
【JAVA优化编程】内存管理之——(3)Java中的析构方法finalize
2011-02-11 11:01 14223 Java中的析构方法finalize ... -
【JAVA优化编程】内存管理之——(2)JVM中对象的生命周期
2011-02-10 16:07 11082 JVM中对象的生命周期 在J ... -
【JAVA优化编程】内存管理之——(1)垃圾回收
2011-02-10 15:04 892内存管理的话题在 ...
相关推荐
《实战Java虚拟机——JVM故障诊断与性能优化》是一本深入探讨Java开发人员和运维人员必备技能的书籍。本书作者葛一鸣以其丰富的实战经验,详细阐述了JVM(Java Virtual Machine)的工作原理,以及如何有效地进行故障...
《实战JAVA虚拟机 JVM故障诊断与性能优化》这本书主要涵盖了Java开发者在实际工作中可能遇到的JVM相关问题,包括但不限于故障排查、性能调优、内存管理、垃圾收集机制等内容。以下将详细介绍这些知识点: 1. **Java...
在这份由Sun Microsystems公司出版的《JVM内存管理白皮书》中,我们可以找到关于Java虚拟机(JVM)内存管理的详细介绍和深入分析。这份文档对于想要深入了解JVM工作原理的读者来说是一份宝贵的学习资料。在这份...
与《高性能Java系统实现与调优.pdf》这本书结合,你可能会学到更多关于Java性能优化的技巧,包括内存管理、垃圾回收、JVM参数调整等方面。书中的内容可能涵盖了如何通过调整系统配置、优化算法和数据结构,以及使用...
掌握JVM的工作原理后,开发者可以进行更高级的调优,如调整JVM参数以优化内存分配、提高垃圾收集效率等。此外,还可以探索JVM的最新特性,如G1垃圾收集器、Metaspace等。 总结,"jvmjava"项目是一个极好的学习资源...
此外,Java还提供了内存调优的手段,例如通过设置JVM参数(如-Xms、-Xmx控制堆内存大小,-XX:NewRatio调整新生代和老年代的比例)来优化内存分配。开发者还可以利用Java的内存分析工具(如VisualVM或JProfiler)来...
在《实战Java虚拟机——JVM故障诊断与性能优化》一书中,作者深入探讨了如何对JVM进行故障排查和性能调优,通过源码分析来帮助读者理解其内部工作原理。下面我们将根据书中的主题,详细阐述相关的知识点。 1. **JVM...
9. **JVM调优**:通过调整JVM参数,可以优化内存分配、垃圾收集策略,提升应用性能。常见的调优参数包括堆大小、新生代与老年代比例、GC算法选择等。 10. **内存分配与访问效率**:Java的内存访问速度与数据存储...
Java是一种广泛使用的面向对象的编程语言,其设计目标是具有高度的可移植性、...在实际面试中,面试官可能会深入询问这些话题,例如垃圾收集的工作机制、内存泄漏的检测与解决,以及如何通过JVM调优来改善应用性能等。
《实战Java虚拟机——JVM故障诊断与性能优化(第2版)》是Java开发者深入理解JVM工作原理、诊断问题以及进行性能调优的重要参考资料。该书籍的源码提供了丰富的示例和实践案例,帮助读者更好地掌握Java虚拟机的内部...
### Java基础之JVM ...以上概述了JVM的基本概念及其核心组成部分,了解这些内容对于深入学习Java编程语言和提升编程效率至关重要。此外,掌握JVM的工作原理还有助于开发者更好地理解和优化Java应用程序的性能问题。
在Java面试中,JVM相关知识是必不可少的一部分,因为理解JVM的工作原理和调优技巧对于开发高效、稳定的Java应用至关重要。下面将详细阐述JVM的一些核心概念和面试常考知识点。 1. **类加载机制**:Java程序的运行...
1. **JVM调优**:Java虚拟机(JVM)是Java程序运行的基础,优化JVM参数可以显著提升性能。例如,调整堆内存大小(-Xms和-Xmx),设置新生代和老年代的比例(-XX:NewRatio),以及开启或关闭垃圾回收器(如G1、Parallel ...
特别地,Java虚拟机(JVM)管理内存的方式使得开发者需要了解一些基本的内存占用知识,以便在进行内存优化和避免内存溢出时能够做出更合理的决策。 首先,文档指出了Java中基本数据类型和对象在内存中的占用大小。在...
- 继续探讨与JVM调优相关的更多概念和技术细节,如内存模型、内存分配策略等。 **1.3 JVM调优总结(三)—基本垃圾回收算法** - 分析几种基本的垃圾回收算法,如标记-清除算法、复制算法、标记-整理算法以及分代...
- **SUN JVM调优**:调优JVM涉及调整其内存分配和垃圾回收策略,以达到最佳的性能和资源利用率。这通常通过设置不同的JVM参数来实现,如-Xms、-Xmx、-XX:+UseConcMarkSweepGC等。 - **JVM简单理解**:JVM的内存模型...
内存管理是JVM工作的一个核心部分,尤其是在垃圾收集机制方面,不同的垃圾收集器(如Serial、Parallel、CMS和G1收集器)针对不同应用场景有着各自的优化策略。书中详细介绍了这些收集器的工作原理及优缺点,为开发者...
目前,Java是最为流行的编程语言之一,它的基础平台就是JVM。除了Java,如JRuby、Scala、Clojure等语言也运行在JVM平台。熟悉和掌握JVM平台有着重要的实用价值和意义。 在本课程中个,将详细介绍JVM的基本原理、...
Java虚拟机(JVM)是Java编程语言的核心组成部分,它为Java程序提供了运行环境。这份JVM相关的笔记包含了深入理解JVM内部工作机制的关键代码资源,是学习和优化Java应用程序的重要参考资料。下面,我们将深入探讨...
同时,讲解了Java中实现并发的基石——JVM内存模型,以及Java提供的并发工具包的基础知识。 第二章:Java并发基础 深入讨论Java中的线程创建与管理,包括Thread类的使用、Runnable接口的实现,以及线程的生命周期...