本文转自: http://spaces.msn.com/songsun/
不同的JVM实现对堆结构的设计有所不同,这里先说说共性的,然后再比较classic vm和hotspot vm在gc方面的差异。
先
大致说说gc的过程,通常有两种情形会导致gc发生,一种是显式的System.gc()调用而java进程未禁止显示gc,第二种是隐式的,即内存管理
器(MM)在alloc内存时发生failure,MM进而作gc以便释放出空间用于分配(当然,假如gc后还是没有空间可满足分配数值,
OutOfMemory就发生了)。gc过程分3步走,第1步,mark阶段,标示出allocbits和markbits,allocbits
代表当前java
heap中存在的对象所占内存的bit映射,markbits代表所有reachable对象所占内存的bit映射,是allocbits的子集。这一
步,一般是要锁定java
heap的,但有些gc器能做到并发/并行mark(后面有解释)。第2步,sweep阶段,即将markbits和allocbits的补集所代表的
内存区域作回收,这也包括对class的回收,假如classgc未被禁用,而jvm确实找到了未被使用的class,那么除了java
heap中的Class对象被回收,method area里该class的method
data也被释放。第3步,compact阶段(可选的,jvm会自行判断是否进行该步),整理碎片,两种技巧,一种是移动琐碎的对象区域,使之连续,
一种是移动琐碎的free区域,也使之连续。这步也必须要锁定java
heap。compact时还要做一个工作,即将所移动的对象的原始引用值作同步更新。这时存在一个问题,假如某thread
stack里的一个浮点数碰巧看起来像是一个对象引用值(内存泄露也会因此情形而发生),那么jvm因为无法断定而放弃移动该对象,等待以后再移动(据
称,hotspot vm对精确判定引用值的问题解决的较好)。
再解释一下mark阶段,为了得到markbits,首先要收集
root references,也就是java thread stacks refs, jni global
refs,thread moniters,interned strings,and soft/weak
refs等,它们是对象引用的源头,从root referent object顺藤摸瓜,即可把所有reachable
object标示出来。再解释一下bits映射,每一个bit代表每一个内存GRAIN(是分配的最小粒度),假设GRAIN是8
byte,那么对于64M的堆,需要额外的1M的bits来映射,这部分额外开支需要gc器向c
heap申请,当堆扩展和收缩时,markbits也要随之变动。mark阶段工作量比较大,因为要扫描和遍历,所以后期的jvm都采用多种新的方式如
concurrent(普通线程也参与mark)或parallel(多cpu有效)进行mark。
再说堆的扩张
(Expansion)和收缩(Shrinkage)。当内存不足时,gc清理一遍后还发现free空间不能满足分配的尺寸要求,那么它有两种手段继续推
进,如果最大堆(-Xmx)未达到,那么扩展堆,如果已达到,那么强制回收soft/weak
referents,如果此时还不能满足,那么OutOfMemory就发生了。而当经过一段运行时间后,jvm判断free区域较多(不同的jvm判
定依据有所不同),那么就会收缩java
heap。收缩的好处有两个,1是减轻OS的负担,2又减少了jvm内存管理器的维护成本。注意,不论再怎么收缩,也不可能小于最小堆(-Xms)。默
认的ms值和mx值各vm提供商有所不同,请参阅其文档。
个人认为主流的jvm主要有3种,sun classic, ibm
classsic,sun hotspot。sun
classsic用于1.3.0以前,之后sun的jvm都是hotspot。而ibm的jdk一直是classsic,不知其5.0的vm是否会采用
hotspot。sun的是主流无可置疑啦,为什么扯上ibm的呢,因为看过一个民间的性能评测结果,ibm
1.42vm比sun的1.42vm甚至略好。sun
classic使用间接句柄分配对象,所以堆分为两部分,一块放object,一块放handle。这个好处是compact方便得很,缺点也是很严重
的缺点,是对象访问不直接,要多一层指针转换,对性能大有影响。ibm classic的具体细节的资料比较缺乏,但根据其white
paper,似乎使用的是直接句柄(否则性能无法比sun的好),另外它将java heap划分成system
heap和一般heap,仅将jvm的系统class和对象分配到system heap里,它还支持并行和并发的gc。sun
hotspot使用直接句柄,似乎又采用了一些高级手段,做到了精确辨别,因此快而且回收准确,另外提供了多种的gc器,适用于不同场合。值得一提的是
它的代生gc器(Generational Copying
Collection),根据对象生命周期模型(小对象居多,生命周期短),使用类似stack的方式,将同一时期产生的对象放在同一容器
(nursery)中,这批对象基本上会同时消亡,这样,回收时可直接将容器释放,避免了繁琐的逐个对象释放的过程,因此可以减少gc的花费时间
(duration)和频度(frequency),并且容器是现成的,所以分配时,寻找free空间很方便,所以提高了分配的效率。
本篇再加上前面的几篇,已经把JVM和Memory相关的主要机理和过程都已经覆盖了,下一篇主要是关于tuning和trouble shooting,请关注。
补:
再说一下内存泄露(memory leak),与c/c++的内存泄露的概念不同,java的memory
leak是指无用(unused)的对象因为仍然是reachable的,所以不能被gc,因而造成内存的被白白占用。造成memory
leak的原因是多样的,比如程序未及时给变量赋null,再比如上文提到的浮点数被碰巧当成对象引用,或者jni程序里声明的global
ref忘了做撤销。对于服务器程序来说,memory
leak的逐渐积累,只要运行时间足够,必然造成OutOfMemory。如何确定jvm是否有内存泄露呢,假使你没有监测工具也不要紧,打开-
verbose:gc开关,运行系统足够长的时间(约收集20到50次gc的数据),然后将verbosegc的信息作收集,察看java
heap的谷值(gc后java heap的大小,峰值则表示gc前java
heap的大小)是否有递增的倾向,如果倾向明显,那么很有可能是memory leak问题。
分享到:
相关推荐
垃圾收集的主要类型有四种,虽然在内容中没有具体提到这四种类型,但在JVM中常见的垃圾收集器包括Serial GC、Parallel GC、CMS(Concurrent Mark Sweep)GC和G1(Garbage-First)GC等。这些垃圾收集器有不同的特性,...
4. **GC调优的目标**:减少Full GC的频率,缩短其执行时间,以及降低STW(Stop-The-World)带来的应用暂停时间。 5. **JVM参数调整**:通过设置JVM参数可以影响GC行为,如`-Xms`和`-Xmx`控制堆内存大小,`-XX:...
《JVM性能调优——JVM内存整理及GC回收》是针对Java开发人员的重要主题,尤其是在大型企业级应用中,确保JVM(Java虚拟机)的高效运行是至关重要的。本资料深入探讨了如何通过调整JVM内存设置和优化垃圾回收机制来...
### JVM体系结构与GC调优 #### 一、JVM体系结构概述 Java虚拟机(JVM)是Java运行环境的基础部分,它为Java程序提供了一个独立于平台的执行环境。JVM的主要职责包括:加载Java类到内存、管理运行时数据区域、执行...
JVM(Java Virtual Machine)的垃圾收集器(GC,Garbage Collector)扮演着核心角色,负责自动管理应用程序的内存,防止内存泄漏和性能问题。MAT(Memory Analyzer Tool)是由Eclipse基金会提供的一个强大的分析工具...
4. **GC次数和时间**:监控GC的触发频率和每次GC所用的时间,有助于识别潜在的性能问题。 5. **内存池(Memory Pool)状态**:了解不同内存区域(如Eden、Survivor、Old等)的使用情况,有助于调整JVM参数以优化性能...
4. **堆(Heap)**:存放所有对象实例及数组,是Java应用中最大的一块内存区域,支持垃圾回收。 5. **方法区(Method Area)/运行时常量池(Runtime Constant Pool)**:存储类的信息,包括类名、方法信息、常量等...
《深入解析MemoryAnalyzer:JVM堆内存分析利器》 在Java开发中,内存管理是至关重要的环节,良好的内存管理能够优化应用性能,防止内存泄漏,提升系统稳定性。MemoryAnalyzer(MAT)是一款强大的JVM堆内存分析工具...
《深入理解MemoryAnalyzer:JVM内存分析利器》 在Java应用程序的开发和优化过程中,内存管理是一项至关重要的任务。MemoryAnalyzer(MAT)是一款强大的JVM内存分析工具,它能够帮助开发者深入洞察应用的内存占用...
5. **GC日志分析**:通过分析JVM产生的GC日志,可以了解垃圾回收的效率和内存使用情况,从而调整参数以优化性能。 6. **内存泄漏检测**:关注长期未被释放的对象,可能暗示存在内存泄漏问题。开发者可以通过工具如...
《JVM Full GC 之 MAT 工具分析实践》 在Java开发中,理解JVM内存管理和垃圾收集机制至关重要,因为这直接关系到应用程序的性能和稳定性。当遇到内存溢出(OutOfMemoryError)、系统异常或者性能下降等问题时,我们...
4. 监控GC日志:通过-XX:+PrintGC、-XX:+PrintGCDetails、-XX:+PrintGCDateStamps等参数,记录并分析垃圾收集行为。 5. 分析内存泄漏:利用内存分析工具,如MAT(Memory Analyzer Tool),对heap dump文件进行深度...
4. 调整Elasticsearch的配置:Elasticsearch本身也提供了一些与GC相关的配置选项,例如调整Elasticsearch节点的通信超时参数(discovery.zen.fd.ping_interval, discovery.zen.fd.ping_timeout, discovery.zen.fd....
内存溢出(Out Of Memory,OOM)是JVM运行过程中常见的问题,主要类型有堆溢出、栈溢出、方法区溢出等。通过分析日志和调整参数可以解决这些问题。 总结,JVM是Java编程的关键组成部分,理解其工作原理、内存模型和...
另外,内存转储分析工具如MAT(Memory Analyzer Tool)和JProfiler等第三方分析工具也可以用来诊断和分析JVM的性能问题。 对于调优的性能指标,通常考虑的有内存占用、启动时间、吞吐量、GC开销和GC暂停时间以及...
通过具体案例,如系统频繁FullGC、String.intern的使用等,可以更加深入理解JVM的运行机制和性能调优方法。 #### 结语 以上是对《JVM必知必会》中涉及的核心知识点的详细梳理。这些内容可以作为学习Java虚拟机的...
- 直接内存(Direct Memory)不是JVM内存的一部分,但通过NIO可以使用,不计入堆内存计算。 了解这些概念有助于优化Java应用性能,减少内存泄漏和提高程序效率。在实际开发中,理解JVM的工作原理对于解决内存问题...