`

JVM内存模型以及垃圾收集策略解析【续】

阅读更多
来自:http://yuquan-nana.iteye.com/blog/599750

三  垃圾收集策略配置

3.1 吞吐量优先

吞吐量是指GC 的时间与运行总时间的比值,比如系统运 行了 100 分钟, 而 GC 占用了一分 钟,那么吞吐量就是 99% , 吞吐量优先一般运用于对响应性要求不高的场合,比如 web 应用,因为网络传输本来就有延迟的问题, GC 造成的短暂的暂停使得用户以为是网络阻塞 所致。

吞吐量优先可以通 过-XX:GCTimeRatio 来 指定。

当通过-XX:GCTimeRatio 不能满足系 统的要求以后,我们可以更加细致的来对 JVM 进 行调优。

首先因为要求高吞吐量,这样就需要一个较大的Young generation ,此时就 需要引入“ Parallel  scavenging  Collector” , 可以通过参数:-XX:UseParallelGC 来配置。

 java -server -Xms3072m -Xmx3072m -XX:NewSize=2560m -XX:MaxNewSize=2560 XX:SurvivorRatio=2 -XX:+UseParallelGC 

当年轻代使用 了"Parallel scavenge collector" 后,老生代就不能使用"CMS"GC 了,在 JDK1.6 之前,此时老生代只能采用串行收集,而 JDK1.6 引入了并行版本的老生代收集器,可以用 参数 -XX:U seParallelOldGC 来配置

3.1.1 控制并行的线程数

缺省情况下,Parallel scavenging Collector  会 开启与 cpu 数量 相同的线程进行并行的收集,但是也可以调节并行的线程数。假如你想用 4 个并行的线程去收集 Young generation 的话,那么就可以配置 -XX:ParallelGCThreads=4, 此 时 JVM 的配置参 数如下:

  java -server -Xms3072m -Xmx3072m -XX:NewSize=2560m -XX:MaxNewSize=2560 XX:SurvivorRatio=2 -XX:+UseParallelGC  -XX:ParallelGCThreads=4

3.1.2 自动调节新生代

在采用了"Parallel scavenge collector" 后, 此 GC 会根据运行 时的情况自动调节 survivor ratio 来 使得性能最优,因此 "Parallel scavenge collector" 应 该总是开启此参数。

此时JVM 的参数配置如下:

java -server -Xms3072m -Xmx3072m -XX:+UseParallelGC     -XX:ParallelGCThreads=4  -XX:+UseAdaptiveSizePolicy

 

3.2 响应时间优先

响应时间优先是指GC 每次运行的时间不能太久,这种情况一般 使用与对及时性要求很高的系统,比如股票系统等。

响应时间优先可以 通过参数-XX:MaxGCPauseMillis 来 配置,配置以后 JVM 将 会自动调节年轻代,老生代的内存分配来满足参数设置。

在一般情况下,JVM 的默认配置就可以满足要求,只有默认 配置不能满足系统的要求时候,才会根据具体的情况来对 JVM 进行性能调优。如果采用默认的配置不能满足系统的要求,那么此时就可以自己动手来调节。

此时"Young generation" 可以采 用 "Parallel copying collector" , 而 "Old generation" 则 可以采用 "Concurrent Collector",

举个例子来说,以 下参数设置了新生代用 Parallel Copying Collector 老生代采用CMS 收集器

java -server -Xms512m -Xmx512m  -XX:NewSize=64m -XX:MaxNewSize=64m -XX:SurvivorRatio=2         - X X:+UseConcMarkSweepGC -XX:+UseParNewGC 

此时需要注意两个问题:

如果没有指定 -XX:+UseParNewGC, 则采用默认的非并行版本的 copy collector.

2  如果在一个单 CPU 的系统上设置了 -XX:+UseParNewGC , 则默认还是采用缺省的copy collector.

3.2.1  控制并行的线程数

默认情况下,Parallel copy collector 启 动和 CPU 数量一 样的线程,也可以通过参数 -XX:ParallelGCThreads 来 指定,比如你想用 3 个 线程去进行并发的复制收集,那么可以改变上述参数如下:

java -server -Xms512m -Xmx512m -XX:NewSize=64m  -XX:MaxNewSize=64m -XX:SurvivorRatio=2        -XX:P arallelGCThreads=4    - X X:+UseConcMarkSweepGC        -XX:+UseParNewGC 

3.2.2  控制并发收集的临界值

默认情况下,CMS gc "old generation" 空间占用率高于 68% 的时候,就会进行垃圾收集,而如果想控制收集 的临界值,可以通过参数: -XX:CMSInitiatingOccupancyFraction 来 控制,比如改变上述的 JVM 配 置如下:

java -server -Xms512m -Xmx512m -XX:NewSize=64m  -XX:MaxNewSize=64m -XX:SurvivorRatio=2        -XX:P arallelGCThreads=4    - X X:+UseConcMarkSweepGC        -XX:+UseParNewGC       -XX:CMSIn itiatingOccupancyFraction=35

 

四 GC 触 发以及常见的内存错误

4.1 Minor GC的触发

Minor GC主 要负责收集 Young Generation Minor GC 一般在新生代不够用的情况 下触发,比如我们一次性创建了很多对象等。

List<byte[]> buffer = new ArrayList<byte[]>(); for(int i=0;i<8*1024;i++){

buffer.add(new byte[1024]);

}

以上代码通过一个 字节数组的List 模拟触发 Minor gc ,设置 JVM 参数如下:

-verbose:gc -Xmn10M -Xms64M -Xmx64M -XX:+PrintGC

设置以上参数以 后,因为-Xmn=10M, 默认 -XX:SurvivorRatio=8  , 则 eden 的空间 大小为 8M ,当 eden 对象大小超过 8M 的时候就会触发 Minor gc.

运行的结果如下:

[GC 8192K->8030K(64512K), 0.0243391 secs]

从运行结果可以看 出,gc 前和 gc 后的 eden 区的占用情况,需要注意的是括号里( 64512) 这个数值时 63M ,它不包括一块 Survivor  空间。

这里需要注意的一 点就是,如果创建的对象大于eden 的 大小,那么将不会通过 Survivor 空 间复制,直接转移到 old generation.

调整以上代码如 下:

List<byte[]> buffer = new ArrayList<byte[]>();

buffer.add(new byte[8*1024*1024]);

通过同样的JVM 参数运行,则发现不会触发 Minor gc ,这是因为对象超过了 eden 的大小,从而直接分配到了 Old generation.

 

4.2 Major GC的触发

4.2.1 Old Generation空间满或者接近某一个比例

Old generation 空 间满是因为 Young generation 提 升到 Old generation 的 对象 +Old generation 的 本来的大小已经接近或者超过了 Old generation 的 大小。对于 CMS GC , 当 Old generation 空 间使用率接近某一个比例,可以通过参数 -XX:CMS InitialingOccupancyFraction , 此参数表示 Old generation 的 使用率,默认为 68%

Young generation对 象提升到 Old generation 对 象有以下三种情况:

Ø  分配的对象大于eden 空间的大小

Ø  Young generation 代中经过了 -XX:MaxTenuringThreshold 次 复制任然存活的对象

Ø  Minor gc的时候,放不 进 to survivor 的 对象

Major GC 以后,如果还没有足够的空间 可以用的话,此时就会抛出 java.lang.OutOfMemory java heap space, 当出现此 错误的时候,说明可能存在内存泄露现象的,这时候就需要我们对程序进行检查看看什么地方存在内存泄露的。

我们可以通过以下 代码来模拟一下java.lang.OutOfMemory:java heap space 的 发生:

List<byte[]> buffer = new ArrayList<byte[]>();

buffer.add(new byte[10*1024*1024]);

以上代码分配了一 个10M 的字节数组,我们通过以下的参数 运行:

-verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC

以上参数指定Young generation 的空间大小为 10M Old generation 空间大小为 10M

运行结果如下:

[GC 327K->134K(19456K), 0.0056516 secs]

[Full GC 134K->134K(19456K), 0.0178891 secs]

[Full GC 134K->131K(19456K), 0.0141412 secs]

Exception in thread "main" java.lang.OutOfMemoryError:   Java heap space

        at Test.main(Test.java:30)

从运行结果可以看 出,JVM 进行了一次 Minor gc 和两次的 Major gc ,从 Major gc 的输出可以看出, gc 以后 old 区使用率为 134K ,而字节数组为 10M ,加起来大于了 old generation 的空间,所以 抛出了异常,如果调整 -Xms21M,-Xmx21M, 那 么就不会触发 gc 操 作也不会出现异常了。

4.2.2 Perm Generation 空间满

Perm Generation空 间主要存放 Class 对 象, Field,Method 对 象,当一次性加载太多的类或者在热部署以后不卸载类的情况(比如在 Jboss 服务器中,如果经常热部署一些应用就会出现 Perm  空间溢出)就会造成 Perm Generation 被占满,此 时就会出现:

java.lang.OutOfMemory:PermGen space,在 出现此异常的时候,如果是因为热部署引起的,我们重新启动 AS 就可以了,如果是因为加载的类太多,此时可以通过 -XX:PermSize -XX:MaxPermSize 调整。

4.3 常见内存错误分析

4.3.1  StackOverflowError 

java.lang.StackOverflowError错 误表示 JVM 栈溢 出,出现这个错误的原因一般都是递归的层次太深,或者无限的递归造成的。出现这种错误的时候首先要对应用程序进行检查,看看是那些代码造成了栈溢出,如果 是递归造成的可以改为迭代方式实现。

JVM同 样也提供了一个参数来让我们调节运行时栈空间的大小。 -XX:Xss=256K 表示栈空间最大为 256 K.我们也可以调大,但是建议不 要对此参数进行调节。

4.3.2  OutOfMemoryError: Java heap space.

java.lang.OutOfMemoryError: Java heap space这 个错误表示 JVM 的 新生代和老生代的内存不足。出现这个错误说明应用程序出现了内存溢出或者程序所需要的内存大于 JVM 的内存设置了。

遇到这个问题的时 候,首先我们可以调节JVM Heap 内存的大小,具体可以通过 -Xmx -Xms来进行设 置,如果设置大以后还是会出现内存溢出,那么说明应用程序本身存在内存泄露,这个时候就需要我们对应用程序进行检查,找出导致内存泄露的地方,然后修正。

4.3.3  OutOfMemory:PermGen space

java.lang.OutOfMemory:PermGen space错 误是由 Perm space 空 间不足。一般出现这个错误是由加载了太多的类或者大量使用了动态代理造成的。如果出现了这个错误,我们可以将 Perm 空间调大一点。

-XX:PermSize= 16 M  -XX:MaxPermSize= 64 M

 

参考资料

1 http://developers.sun.com/mobility/midp/articles/garbage/

2 http://developers.sun.com/mobility/midp/articles/garbagecollection2/

3 http://blogs.sun.com/watt/resource/jvm-options-list.html

4 http://java.sun.com/developer/technicalArticles/Programming/turbo/

5 http://www.ibm.com/developerworks/library/j-jtp10283/index.html?S_TACT=105AGX52&S_CMP=cn-a-j

6 http://www.ibm.com/developerworks/library/j-jtp11253/index.html?S_TACT=105AGX52&S_CMP=cn-a-j

分享到:
评论

相关推荐

    JVM内存模型以及垃圾收集策略解析

    JVM内存模型以及垃圾收集策略解析 可以深入了解java虚拟机的原理

    JVM内存模型及垃圾收集策略解析

    NULL 博文链接:https://forrest420.iteye.com/blog/1127427

    深入理解JVM内存结构及运行原理全套视频加资料.txt

    2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...

    Java面试通关宝典:深度解读核心知识点与实战技巧,全面提升面试表现力与技术实力

    JVM与性能优化:这部分问题涵盖了JVM内存模型、垃圾收集、性能调优等内容。例如,解释JVM的内存区域划分和作用;理解垃圾收集算法和调优策略;讨论如何分析和优化Java应用程序的性能等。 通过深入学习和理解这些问题...

    zxing.java源码解析-JavaAndroidInterview:Android、JavaSE、数据结构与算法豆知识,可用于碎片化学习和

    zxing.java源码解析 这是一个JavaSE、Android领域的豆知识tips,可以用来...JVM内存模型和垃圾收集 3. 垃圾收集策略 4. G1收集器 5. Java引用类型 网络传输 正则表达式 Git 计算机组成原理(正在填补中……) 言职 附录:

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    112 5.2.5 服务器JVM进程崩溃 / 113 5.3 实战:Eclipse运行速度调优 / 114 5.3.1 调优前的程序运行状态 / 114 5.3.2 升级JDK 1.6的性能变化及兼容问题 / 117 5.3.3 编译时间和类加载时间的优化 / 122 5.3.4 ...

    Java虚拟机

    第五部分探讨了Java实现高效并发的原理,包括JVM内存模型的结构和操作;原子性、可见性和有序性在Java内存模型中的体现;先行发生原则的规则和使用;线程在Java语言中的实现原理;虚拟机实现高效并发所做的一系列锁...

    Hadoop实战(第2版)

    9.3.4 其他Mahout clustering 算法 .9.4 本章小结第5 部分 驯服大象10 深入解析 Hive10.1 Hive 基础10.1.1 安装10.1.2 元存储10.1.3 数据库、表、分区和存储10.1.4 数据模型10.1.5 查询...

    Hadoop硬实战 [(美)霍姆斯著][电子工业出版社][2015.01]_PDF电子书下载 带书签目录 高清完整版.rar )

    4.1.4 为你的数据挑选最优的合并策略 4.2 排序 4.2.1 二次排序 技术点21 二次排序的实现 4.2.2 整体并行排序 技术点22 通过多个reducer 对key 进行排序 4.3 抽样 技术点23 蓄水池抽样(reservoir ...

    java 面试题 总结

     GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...

    超级有影响力霸气的Java面试题大全文档

     GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收...

    java核心知识点整理.pdf

    JVM 内存区域 ..................................................................................................................................... 21 2.2.1. 程序计数器(线程私有) ........................

    JAVA核心知识点整理(有效)

    2.2. JVM 内存区域 ..................................................................................................................................... 21 2.2.1. 程序计数器(线程私有) ....................

Global site tag (gtag.js) - Google Analytics