- 浏览: 3053507 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
把先前在论坛回复的一些帖打捞进来。这篇的原帖是:HotSpot VM 内存堆的两个Survivor区
下面是回复内容,带补充。
=================================================================
1、根本的区别之一:System.gc()可能在自动GC原本不会进入GC的位置上进入GC。
正常情况下,Java代码要尝试在GC堆上分配空间的时候才会触发GC;换句话说,基本上是“new”(或者类似的会隐式在GC堆上分配空间)的时候才会触发GC。但System.gc()、JVMTI的强制GC等动作都在正常情况之外提示系统要做一次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,/就知道了:
这样grep出来的启动参数中,UseMaximumCompactionOnSystemGC和UseAdaptiveSizePolicyWithSystemGC不是选择GC算法类型的参数,另外几个都是。它们分别是
·UseSerialGC
·UseG1GC
·UseParallelGC
·UseParallelOldGC
·UseAsyncConcMarkSweepGC(产品模式不可调)
·UseConcMarkSweepGC
·UseParNewGC
它们之间的关系请参考:Jon Masamitsu: Our Collectors
Sun(=> Oracle)的产品版JDK 6里的HotSpot同上。
------------------
JRockit R28的话,GC算法的基本设定可以用下面几个参数:
不过更推荐并且也更简单的是设定优化的目标,例如这几个参数:
-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
下面是回复内容,带补充。
=================================================================
kingkan 写道
请教下前辈们:
1.手动System.gc()与JVM自动gc有什么根本上的区别么?在程序里面一个对象用完的时候,马上使用System.gc(),通过内存使用数据查看,该对象的内存是还没释放的。但是对象使用完,马上设置为null,再System.gc(),该对象的内存就被释放了,不解。
2.用户能自己设置JVM选择何种GC算法来进行GC么?
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
发表评论
-
The Prehistory of Java, HotSpot and Train
2014-06-02 08:18 0http://cs.gmu.edu/cne/itcore/vi ... -
MSJVM and Sun 1.0.x/1.1.x
2014-05-20 18:50 0当年的survey paper: http://www.sym ... -
Sun JDK1.4.2_28有TieredCompilation
2014-05-12 08:48 0原来以前Sun的JDK 1.4.2 update 28就已经有 ... -
IBM JVM notes (2014 ver)
2014-05-11 07:16 0Sovereign JIT http://publib.bou ... -
class data sharing by Apple
2014-03-28 05:17 0class data sharing is implement ... -
HotSpot Server VM与Server Class Machine
2014-02-18 13:21 0HotSpot VM历来有Client VM与Server V ... -
Java 8的lambda表达式在OpenJDK8中的实现
2014-02-04 12:08 0三月份JDK8就要发布首发了,现在JDK8 release c ... -
GC stack map与deopt stack map的异同
2014-01-08 09:56 0两者之间不并存在包含关系。它们有交集,但也各自有特别的地方。 ... -
HotSpot Server Compiler与data-flow analysis
2014-01-07 17:41 0http://en.wikipedia.org/wiki/Da ... -
基于LLVM实现VM的JIT的一些痛点
2014-01-07 17:25 0同事Philip Reames Sanjoy Das http ... -
tailcall notes
2013-12-27 07:42 0http://blogs.msdn.com/b/clrcode ... -
《自制编程语言》的一些笔记
2013-11-24 00:20 0http://kmaebashi.com/programmer ... -
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22410(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局 (0): 拿在手上的是什么
2013-11-04 18:22 21511(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
Java的instanceof是如何实现的
2013-09-22 16:57 0Java语言规范,Java SE 7版 http://docs ... -
也谈类型: 数据, 类型, 标签
2013-08-18 01:59 0numeric tower http://en.wikiped ... -
oop、klass、handle的关系
2013-07-30 17:34 0oopDesc及其子类的实例 oop : oopDesc* ... -
Nashorn各种笔记
2013-07-15 17:03 0http://bits.netbeans.org/netbea ...
相关推荐
### Java SE 6与HotSpot VM故障排除指南关键知识点解析 #### 一、概述 《Java SE 6与HotSpot VM故障排除指南》是Oracle公司于2008年11月发布的一份技术文档,旨在帮助开发人员、系统管理员和技术支持人员解决在...
在HotSpot VM中,新生代通常分为Eden区和两个Survivor区(From和To)。Minor GC主要负责清理Eden区和一个Survivor区的对象。存活下来的对象会被移动到另一个Survivor区或者老年代。 在Serial GC中,FastScanClosure...
读书笔记:hotspot实战 code
总的来说,HSDB是HotSpot VM的一个强大工具,它提供了丰富的功能来探索和理解JVM的运行时数据,包括内存布局、对象状态以及垃圾收集行为等。熟练掌握HSDB的使用,将极大地提升开发者对Java应用性能调优的能力。
读书笔记:hotspot实战的测试demo
2. 内存管理:HotSpot将内存分为堆(Heap)和非堆(Non-Heap)两部分,堆内存主要用于对象实例的存储,非堆内存则包含方法区和JVM自身的数据结构。源码中,`MemoryManager`与`GarbageCollector`密切合作,实现内存...
Hotspot有两个JIT编译器:Client Compiler(C1)和Server Compiler(C2)。C1适用于快速启动,而C2则更注重长期性能。 二、垃圾收集器 Hotspot JVM提供了多种垃圾收集器,如Serial、Parallel、Concurrent Mark ...
5. **内存模型**:HotSpot虚拟机内存分为堆(Heap)、栈(Stack)、方法区(Method Area)和本地方法栈(Native Method Stack)等区域,书中会解释各部分的作用,以及如何调整内存参数以优化性能。 6. **性能监控和...
- **分代假设**:HotSpot基于对象存活时间的不同将其划分为年轻代和老年代,年轻代又细分为Eden区和Survivor区。 - **不同的垃圾回收算法**:包括Serial、ParNew、Parallel Scavenge、CMS、G1等不同类型的垃圾回收...
HotSpot JVM 中的即时编译器可以分为两个部分:C1 编译器和 C2 编译器。C1 编译器是一个简单的编译器,用于编译小型方法,而 C2 编译器是一个高级编译器,用于编译大型方法。 除了即时编译外,HotSpot JVM 还支持 ...
1. **t1**: 作为静态变量,`t1`存储在方法区(Method Area),在HotSpot VM中,这部分内存区域对应于"非堆"内存,用于存放类的信息,包括类的静态变量、常量池等。 2. **t2**: `t2`是`Test`类的一个实例变量,因此...
在HotSpot VM中,静态变量实际存储在非堆内存的一个特殊区域,这部分内存并不受垃圾收集器管理。 2. **实例变量t2**:实例变量属于对象的一部分,当创建一个对象Test的实例时,t2会被分配到Java堆中。Java堆是JVM...
1. **Java HotSpot虚拟机的JIT编译**:HotSpot是Java虚拟机的一个实现版本,由Oracle公司开发。它对运行在Java平台上的应用程序执行高效的JIT编译,将Java字节码转换成本地机器码以提高性能。JIT编译能够在程序运行...
【标题】"hotspot-8.rar" 涉及的核心知识点是HotSpot虚拟机和JVM(Java Virtual Machine)的学习,这是一款由Oracle公司开发的Java虚拟机实现,广泛应用于Java程序的运行与优化。HotSpot是Java平台的重要组成部分,...
堆内存又细分为年轻代(新生代)和老年代,年轻代包括Eden区、Survivor区(From和To),老年代存储生命周期较长的对象。 4. **垃圾收集器类型**:HotSpot提供了多种GC策略,如Serial GC、Parallel GC、Parallel Old...
2. **解释器与即时编译器**:Hotspot采用混合执行模式,既包含解释器来快速启动程序,又包含了C1和C2两个不同的即时编译器(Just-In-Time,JIT),用于将字节码转化为机器码,提高执行效率。 3. **垃圾收集器**:...
5. **内存管理**:包括堆分配、对象生命周期管理、内存对齐等,是JVM性能的关键因素。 6. **编译器优化**:Hotspot包含各种优化技术,如逃逸分析、标量替换、循环展开等,以提升编译后的代码性能。 7. **线程和...
4. **内存模型**:了解Java内存模型(JMM)和Hotspot中的堆内存布局,包括新生代、老年代、永久代(或元空间)等区域,有助于优化内存使用。 5. **线程与并发**:Hotspot支持多线程并发,其内部实现了线程调度和...
4. **内存管理**:Hotspot源码中包含了堆内存的分配、对象的创建和生命周期管理。`memory目录`和`oops目录`包含了对象相关的数据结构和内存管理策略。 5. **类加载器**:源码中的`classfile目录`和`share/vm/class...