`
RednaxelaFX
  • 浏览: 3053507 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

答复: HotSpot VM 内存堆的两个Survivor区

阅读更多
把先前在论坛回复的一些帖打捞进来。这篇的原帖是:HotSpot VM 内存堆的两个Survivor区
下面是回复内容,带补充。

=================================================================

kingkan 写道
请教下前辈们:

1.手动System.gc()与JVM自动gc有什么根本上的区别么?在程序里面一个对象用完的时候,马上使用System.gc(),通过内存使用数据查看,该对象的内存是还没释放的。但是对象使用完,马上设置为null,再System.gc(),该对象的内存就被释放了,不解。

2.用户能自己设置JVM选择何种GC算法来进行GC么?

1、根本的区别之一:System.gc()可能在自动GC原本不会进入GC的位置上进入GC。
正常情况下,Java代码要尝试在GC堆上分配空间的时候才会触发GC;换句话说,基本上是“new”(或者类似的会隐式在GC堆上分配空间)的时候才会触发GC。但System.gc()、JVMTI的强制GC等动作都在正常情况之外提示系统要做一次GC。
kingkan 写道
在程序里面一个对象用完的时候,马上使用System.gc(),通过内存使用数据查看,该对象的内存是还没释放的。但是对象使用完,马上设置为null,再System.gc(),该对象的内存就被释放了,不解。

这个情况即便在HotSpot上也不一定,要看被测的方法有没有被JIT编译过。解释执行的时候基本上没啥优化,所以局部变量的存活范围跟源码里看起来是一致的。但因为HotSpot的JIT编译带有优化,一个局部变量在一个方法里被使用过的赋值才会有效,而未被使用过的赋值很可能被消除掉。这样,在方法最后把局部变量设为null就是徒劳的,赋值动作本身都会被消除。事实上不需要额外的赋值为null的动作,JIT编译器也会尽可能的缩小变量的有效范围,所以完全没必要在方法末尾将局部变量置null。
在.NET的CLR上,由于方法总是要被编译了才可以执行(AOT或者JIT),而且编译也带有优化,源码里变量的引用状况跟实际运行时的引用状况的差异可能更明显些,像这个例子就比较极端。

2011-07-11补充:Peter Burka发了篇博文也提到了对象的生命周期可能比源码上看起来的要短的情况,A subtle issue of reachability

话说回来,Runtime.totalMemory()和Runtime.freeMemory()都是很RP的方法,其实并不适合细粒度观察…不知道您是用什么方式来“通过内存使用数据查看,该对象的内存是还没释放的”呢?
HotSpot默认会对方法调用次数的计数器做“衰减”,每进一次GC就会检查是否已到半衰周期,到了就会把所有方法的调用次数的计数器减半。如果写microbenchmark的话,在被测的方法里插入System.gc()很可能会带来干扰,使被测方法的调用次数始终达不到编译的条件,导致其不被JIT编译。要禁用计数器衰减的话,启动VM的时候要给参数-XX:-UseCounterDecay。要确认某个方法有没有被JIT编译请使用-XX:+PrintCompilation
靠microbenchmark来观察某个对象有没有被GC回收多半是不准确的。可以具体情况具体分析。

另外值得注意的是,System.gc()不一定是触发所谓的“full GC”或者叫“major GC”。
在Sun JDK6与OpenJDK 6的HotSpot里,"GCCause_java_lang_system_gc"的时候,如果VM启动参数DisableExplicitGC为false,则会触发一次full GC,如果该参数为true则完全不触发任何GC。要将这个参数设置为true,启动的时候写上-XX:+DisableExplicitGC就行。
HotSpot对System.gc()有特别处理,最主要的地方体现在一次System.gc()是否与普通GC一样会触发GC的统计/阈值数据的更新——HotSpot里的许多GC算法都带有自适应的功能,会根据先前收集的效率来决定接下来的GC中使用的参数,但System.gc()默认不更新这些统计数据,避免用户强行调用GC对这些自适应功能的干扰(可以参考HotSpot的UseAdaptiveSizePolicyWithSystemGC参数,默认是false)。除此之外,在HotSpot里,System.gc()所触发的full GC跟普通的full GC没啥大差别。
当使用Concurrent Mark-Sweep (CMS)时,可以通过-XX:+ExplicitGCInvokesConcurrent-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses 参数来指定System.gc()触发并发GC而不是full GC。在CMS中,并发GC不对old gen做压缩,而full GC是stop-the-world的并且会做压缩。

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

在Oracle JRockit里,System.gc()触发的是nursery GC(如果选择了分代GC的话;如果选择的不是分代式GC算法则谈不上nursery还是old)。与HotSpot相同,可以通过一个参数禁用System.gc():-XXnoSystemGC。也可以通过另一个参数来强制System.gc()做full GC:-XXfullSystemGC
JRockit R28里,禁用System.gc()的推荐参数是-XX:AllowSystemGC=false,而设定System.gc()触发full GC的参数是-XX:FullSystemGC=true

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

在IBM JDK的JVM里,System.gc()同样可以禁用——使用-Xdisableexplicitgc参数。另外也有一些可以调节System.gc()触发的GC内容的参数,如-Xcompactexplicitgc、-Xnocompactexplicitgc之类。

============================================================

2、对OpenJDK 6里的HotSpot VM,请看这个文件,grep出/Use.*GC,/就知道了:
curl 'http://hg.openjdk.java.net/jdk6/jdk6/hotspot/raw-file/tip/src/share/vm/runtime/globals.hpp' | grep -A 2 -E 'Use.*GC,'

  product(bool, UseSerialGC, false,                                         \
          "Use the serial garbage collector")                               \
                                                                            \
  product(bool, UseG1GC, false,                                             \
          "Use the Garbage-First garbage collector")                        \
                                                                            \
  product(bool, UseParallelGC, false,                                       \
          "Use the Parallel Scavenge garbage collector")                    \
                                                                            \
  product(bool, UseParallelOldGC, false,                                    \
          "Use the Parallel Old garbage collector")                         \
                                                                            \
--
  product(bool, UseMaximumCompactionOnSystemGC, true,                       \
          "In the Parallel Old garbage collector maximum compaction for "   \
          "a system GC")                                                    \
--
  product(bool, UseConcMarkSweepGC, false,                                  \
          "Use Concurrent Mark-Sweep GC in the old generation")             \
                                                                            \
--
  develop(bool, UseAsyncConcMarkSweepGC, true,                              \
          "Use Asynchronous Concurrent Mark-Sweep GC in the old generation")\
                                                                            \
--
  product(bool, UseParNewGC, false,                                         \
          "Use parallel threads in the new generation.")                    \
                                                                            \
--
  product(bool, UseAdaptiveSizePolicyWithSystemGC, false,                   \
          "Use statistics from System.GC for adaptive size policy")         \
                                                                            \

这样grep出来的启动参数中,UseMaximumCompactionOnSystemGC和UseAdaptiveSizePolicyWithSystemGC不是选择GC算法类型的参数,另外几个都是。它们分别是
·UseSerialGC
·UseG1GC
·UseParallelGC
·UseParallelOldGC
·UseAsyncConcMarkSweepGC(产品模式不可调)
·UseConcMarkSweepGC
·UseParNewGC
它们之间的关系请参考:Jon Masamitsu: Our Collectors
Jon Masamitsu 写道


Sun(=> Oracle)的产品版JDK 6里的HotSpot同上。

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

JRockit R28的话,GC算法的基本设定可以用下面几个参数:
参数名 意义
-Xgc:singlecon 或 -Xgc:singleconcon Concurrent Mark & Sweep 不分代,并发收集
-Xgc:gencon 或 -Xgc:genconcon Generational Concurrent Mark & Sweep 分代式,并发收集
-Xgc:parallel 或 -Xgc:singlepar 或 -Xgc:singleparpar Parallel Mark & Sweep 不分代,并行收集
-Xgc:genpar 或 -Xgc:genparpar Generational Parallel Mark & Sweep 分代式,并行收集
-Xgc:singleconpar Concurrent Mark, Parallel Sweep
-Xgc:genconpar Generational Concurrent Mark, Parallel Sweep
-Xgc:singleparcon Parallel Mark, Concurrent Sweep
-Xgc:genparcon Generational Parallel Mark, Concurrent Sweep

不过更推荐并且也更简单的是设定优化的目标,例如这几个参数:
-XgcPrio:throughput
-XgcPrio:pausetime
-XgcPrio:deterministic

老帖描述了当时的JRockit该如何选择GC实现
JRockit很有趣的一点是,当用户指定的是GC“模式”而不是具体的GC“策略”时,JRockit有可能在运行时根据运行状态改变具体的GC“策略”(只有选择了singlepar时无法改变策略,因为这个策略不需要write barrier但其它策略都需要)。

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

IBM J9有诸如下面几种设定GC算法的VM参数:
-Xgcpolicy:optthruput
-Xgcpolicy:optavgpause
-Xgcpolicy:gencon
-Xgcpolicy:subpool
分享到:
评论

相关推荐

    Troubleshooting Guide for Java SE 6 with HotSpot VM

    ### Java SE 6与HotSpot VM故障排除指南关键知识点解析 #### 一、概述 《Java SE 6与HotSpot VM故障排除指南》是Oracle公司于2008年11月发布的一份技术文档,旨在帮助开发人员、系统管理员和技术支持人员解决在...

    hllvm.HotSpot VM Serial GC的一个问题1

    在HotSpot VM中,新生代通常分为Eden区和两个Survivor区(From和To)。Minor GC主要负责清理Eden区和一个Survivor区的对象。存活下来的对象会被移动到另一个Survivor区或者老年代。 在Serial GC中,FastScanClosure...

    读书笔记:hotspot实战 code.zip

    读书笔记:hotspot实战 code

    借HSDB来探索HotSpot VM的运行时数据.gist1

    总的来说,HSDB是HotSpot VM的一个强大工具,它提供了丰富的功能来探索和理解JVM的运行时数据,包括内存布局、对象状态以及垃圾收集行为等。熟练掌握HSDB的使用,将极大地提升开发者对Java应用性能调优的能力。

    读书笔记:hotspot实战的测试demo.zip

    读书笔记:hotspot实战的测试demo

    hotspot源码

    2. 内存管理:HotSpot将内存分为堆(Heap)和非堆(Non-Heap)两部分,堆内存主要用于对象实例的存储,非堆内存则包含方法区和JVM自身的数据结构。源码中,`MemoryManager`与`GarbageCollector`密切合作,实现内存...

    hotspot.tar.gz

    Hotspot有两个JIT编译器:Client Compiler(C1)和Server Compiler(C2)。C1适用于快速启动,而C2则更注重长期性能。 二、垃圾收集器 Hotspot JVM提供了多种垃圾收集器,如Serial、Parallel、Concurrent Mark ...

    《HotSpot实战》

    5. **内存模型**:HotSpot虚拟机内存分为堆(Heap)、栈(Stack)、方法区(Method Area)和本地方法栈(Native Method Stack)等区域,书中会解释各部分的作用,以及如何调整内存参数以优化性能。 6. **性能监控和...

    [百度网盘] HotSpot实战[完整版][带书签].pdf

    - **分代假设**:HotSpot基于对象存活时间的不同将其划分为年轻代和老年代,年轻代又细分为Eden区和Survivor区。 - **不同的垃圾回收算法**:包括Serial、ParNew、Parallel Scavenge、CMS、G1等不同类型的垃圾回收...

    Compilation in the HotSpot VM-Zoltan-Majo.pdf

    HotSpot JVM 中的即时编译器可以分为两个部分:C1 编译器和 C2 编译器。C1 编译器是一个简单的编译器,用于编译小型方法,而 C2 编译器是一个高级编译器,用于编译大型方法。 除了即时编译外,HotSpot JVM 还支持 ...

    借HSDB来探索HotSpot VM的运行时数据1

    1. **t1**: 作为静态变量,`t1`存储在方法区(Method Area),在HotSpot VM中,这部分内存区域对应于"非堆"内存,用于存放类的信息,包括类的静态变量、常量池等。 2. **t2**: `t2`是`Test`类的一个实例变量,因此...

    hllvm.借HSDB来探索HotSpot VM的运行时数据1

    在HotSpot VM中,静态变量实际存储在非堆内存的一个特殊区域,这部分内存并不受垃圾收集器管理。 2. **实例变量t2**:实例变量属于对象的一部分,当创建一个对象Test的实例时,t2会被分配到Java堆中。Java堆是JVM...

    The Java HotSpot VM.pdf

    1. **Java HotSpot虚拟机的JIT编译**:HotSpot是Java虚拟机的一个实现版本,由Oracle公司开发。它对运行在Java平台上的应用程序执行高效的JIT编译,将Java字节码转换成本地机器码以提高性能。JIT编译能够在程序运行...

    hotspot-8.rar

    【标题】"hotspot-8.rar" 涉及的核心知识点是HotSpot虚拟机和JVM(Java Virtual Machine)的学习,这是一款由Oracle公司开发的Java虚拟机实现,广泛应用于Java程序的运行与优化。HotSpot是Java平台的重要组成部分,...

    jdk20-hotspot-virtual-machine-garbage-collection-tuni

    堆内存又细分为年轻代(新生代)和老年代,年轻代包括Eden区、Survivor区(From和To),老年代存储生命周期较长的对象。 4. **垃圾收集器类型**:HotSpot提供了多种GC策略,如Serial GC、Parallel GC、Parallel Old...

    hotspot源代码

    2. **解释器与即时编译器**:Hotspot采用混合执行模式,既包含解释器来快速启动程序,又包含了C1和C2两个不同的即时编译器(Just-In-Time,JIT),用于将字节码转化为机器码,提高执行效率。 3. **垃圾收集器**:...

    openjdk hotspot源码

    5. **内存管理**:包括堆分配、对象生命周期管理、内存对齐等,是JVM性能的关键因素。 6. **编译器优化**:Hotspot包含各种优化技术,如逃逸分析、标量替换、循环展开等,以提升编译后的代码性能。 7. **线程和...

    hotspot1.7.rar

    4. **内存模型**:了解Java内存模型(JMM)和Hotspot中的堆内存布局,包括新生代、老年代、永久代(或元空间)等区域,有助于优化内存使用。 5. **线程与并发**:Hotspot支持多线程并发,其内部实现了线程调度和...

    Hotspot源码

    4. **内存管理**:Hotspot源码中包含了堆内存的分配、对象的创建和生命周期管理。`memory目录`和`oops目录`包含了对象相关的数据结构和内存管理策略。 5. **类加载器**:源码中的`classfile目录`和`share/vm/class...

Global site tag (gtag.js) - Google Analytics