- 浏览: 662089 次
- 性别:
- 来自: 宇宙中的某个角落
文章分类
- 全部博客 (244)
- Java SE (57)
- EJB3.0 (7)
- Architecture (15)
- DDD (4)
- UML&GOF Patterns (17)
- scala (0)
- hadoop (1)
- Hibernate&JPA (8)
- webwork (2)
- Problems and Solution (3)
- search engine (Lucene) (4)
- .net C# (2)
- Web develop (9)
- OS(windows&linux) (2)
- Software Engineering (0)
- Resource shara (5)
- Javascript (1)
- apple (1)
- Data structure (11)
- English study (32)
- Assembly language (2)
- Feeling&emotion (5)
- Diary (23)
- Entertainment (17)
- 诗词赏析 (8)
- 道德经 (1)
- ios (5)
最新评论
-
zhuzf:
写的太好了
实例分析Java Class的文件结构 -
随便小屋:
写的太好了,Mark一下,楼主辛苦了!
实例分析Java Class的文件结构 -
lowkey2046:
引用 应用程序注册读就需事件和相关联的事件处理器应该是读就绪吧 ...
高性能IO设计的Reactor和Proactor模式 -
BigBird2012:
“JVM引入了分代收集的策略,其中对新生代采用"Ma ...
JVM内存模型以及垃圾收集策略解析 -
xuelian2010:
找到合适的人做正确的事情!!!
三月份辞职创业,北京第一家线下体验店成功开张,伙伴们加油!
首先祝大家春节愉快,几个月前研究了一下JVM的内存模型,整理学习心得,共享出来和大家一起学习讨论进步。
一 JVM内存模型
1.1 Java栈
Java栈是与每一个线程关联的,JVM在创建每一个线程的时候,会分配一定的栈空间给线程。它主要用来存储线程执行过程中的局部变量,方法的返回值,以及方法调用上下文。栈空间随着线程的终止而释放。
StackOverflowError:如果在线程执行的过程中,栈空间不够用,那么JVM就会抛出此异常,这种情况一般是死递归造成的。
1.2 堆
Java中堆是由所有的线程共享的一块内存区域,堆用来保存各种JAVA对象,比如数组,线程对象等。
1.2.1 Generation
JVM堆一般又可以分为以下三部分:
Ø Perm
Perm代主要保存class,method,filed对象,这部门的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。
Ø Tenured
Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。
Ø Young
Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,其中Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Young区间变满的时候,minor GC就会将存活的对象移到空闲的Survivor区间中,根据JVM的策略,在经过几次垃圾收集后,任然存活于Survivor的对象将被移动到Tenured区间。
1.2.2 Sizing the Generations
JVM提供了相应的参数来对内存大小进行配置。
正如上面描述,JVM中堆被分为了3个大的区间,同时JVM也提供了一些选项对Young,Tenured的大小进行控制。
Ø Total Heap
-Xms :指定了JVM初始启动以后初始化内存
-Xmx:指定JVM堆得最大内存,在JVM启动以后,会分配-Xmx参数指定大小的内存给JVM,但是不一定全部使用,JVM会根据-Xms参数来调节真正用于JVM的内存
-Xmx -Xms之差就是三个Virtual空间的大小
Ø Young Generation
-XX:NewRatio=8意味着tenured 和 young的比值8:1,这样eden+2*survivor=1/9
堆内存
-XX:SurvivorRatio=32意味着eden和一个survivor的比值是32:1,这样一个Survivor就占Young区的1/34.
-Xmn 参数设置了年轻代的大小
Ø Perm Generation
-XX:PermSize=16M -XX:MaxPermSize=64M
Thread Stack
-XX:Xss=128K
1.3 堆栈分离的好处
呵呵,其它的先不说了,就来说说面向对象的设计吧,当然除了面向对象的设计带来的维护性,复用性和扩展性方面的好处外,我们看看面向对象如何巧妙的利用了堆栈分离。如果从JAVA内存模型的角度去理解面向对象的设计,我们就会发现对象它完美的表示了堆和栈,对象的数据放在堆中,而我们编写的那些方法一般都是运行在栈中,因此面向对象的设计是一种非常完美的设计方式,它完美的统一了数据存储和运行。
二 JAVA垃圾收集器
2.1 垃圾收集简史
垃圾收集提供了内存管理的机制,使得应用程序不需要在关注内存如何释放,内存用完后,垃圾收集会进行收集,这样就减轻了因为人为的管理内存而造成的错误,比如在C++语言里,出现内存泄露时很常见的。
Java语言是目前使用最多的依赖于垃圾收集器的语言,但是垃圾收集器策略从20世纪60年代就已经流行起来了,比如Smalltalk,Eiffel等编程语言也集成了垃圾收集器的机制。
2.2 常见的垃圾收集策略
所有的垃圾收集算法都面临同一个问题,那就是找出应用程序不可到达的内存块,将其释放,这里面得不可到达主要是指应用程序已经没有内存块的引用了,而在JAVA中,某个对象对应用程序是可到达的是指:这个对象被根(根主要是指类的静态变量,或者活跃在所有线程栈的对象的引用)引用或者对象被另一个可到达的对象引用。
2.2.1 Reference Counting(引用计数)
引用计数是最简单直接的一种方式,这种方式在每一个对象中增加一个引用的计数,这个计数代表当前程序有多少个引用引用了此对象,如果此对象的引用计数变为0,那么此对象就可以作为垃圾收集器的目标对象来收集。
优点:
简单,直接,不需要暂停整个应用
缺点:
1.需要编译器的配合,编译器要生成特殊的指令来进行引用计数的操作,比如每次将对象赋值给新的引用,或者者对象的引用超出了作用域等。
2.不能处理循环引用的问题
2.2.2 跟踪收集器
跟踪收集器首先要暂停整个应用程序,然后开始从根对象扫描整个堆,判断扫描的对象是否有对象引用,这里面有三个问题需要搞清楚:
1.如果每次扫描整个堆,那么势必让GC的时间变长,从而影响了应用本身的执行。因此在JVM里面采用了分代收集,在新生代收集的时候minor gc只需要扫描新生代,而不需要扫描老生代。
2.JVM采用了分代收集以后,minor gc只扫描新生代,但是minor gc怎么判断是否有老生代的对象引用了新生代的对象,JVM采用了卡片标记的策略,卡片标记将老生代分成了一块一块的,划分以后的每一个块就叫做一个卡片,JVM采用卡表维护了每一个块的状态,当JAVA程序运行的时候,如果发现老生代对象引用或者释放了新生代对象的引用,那么就JVM就将卡表的状态设置为脏状态,这样每次minor gc的时候就会只扫描被标记为脏状态的卡片,而不需要扫描整个堆。具体如下图:
3.GC在收集一个对象的时候会判断是否有引用指向对象,在JAVA中的引用主要有四种:Strong reference,Soft reference,Weak reference,Phantom reference.
Ø Strong Reference
强引用是JAVA中默认采用的一种方式,我们平时创建的引用都属于强引用。如果一个对象没有强引用,那么对象就会被回收。
public void testStrongReference(){
Object referent = new Object();
Object strongReference = referent;
referent = null;
System.gc();
assertNotNull(strongReference);
}
Ø Soft Reference
软引用的对象在GC的时候不会被回收,只有当内存不够用的时候才会真正的回收,因此软引用适合缓存的场合,这样使得缓存中的对象可以尽量的再内存中待长久一点。
Public void testSoftReference(){
String str = "test";
SoftReference<String> softreference = new SoftReference<String>(str);
str=null;
System.gc();
assertNotNull(softreference.get());
}
Ø Weak reference
弱引用有利于对象更快的被回收,假如一个对象没有强引用只有弱引用,那么在GC后,这个对象肯定会被回收。
Public void testWeakReference(){
String str = "test";
WeakReference<String> weakReference = new WeakReference<String>(str);
str=null;
System.gc();
assertNull(weakReference.get());
}
Ø Phantom reference
2.2.2.1 Mark-Sweep Collector(标记-清除收集器)
标记清除收集器最早由Lisp的发明人于1960年提出,标记清除收集器停止所有的工作,从根扫描每个活跃的对象,然后标记扫描过的对象,标记完成以后,清除那些没有被标记的对象。
优点:
1 解决循环引用的问题
2 不需要编译器的配合,从而就不执行额外的指令
缺点:
1.每个活跃的对象都要进行扫描,收集暂停的时间比较长。
2.2.2.2 Copying Collector(复制收集器)
复制收集器将内存分为两块一样大小空间,某一个时刻,只有一个空间处于活跃的状态,当活跃的空间满的时候,GC就会将活跃的对象复制到未使用的空间中去,原来不活跃的空间就变为了活跃的空间。
复制收集器具体过程可以参考下图:
优点:
1 只扫描可以到达的对象,不需要扫描所有的对象,从而减少了应用暂停的时间
缺点:
1.需要额外的空间消耗,某一个时刻,总是有一块内存处于未使用状态
2.复制对象需要一定的开销
2.2.2.3 Mark-Compact Collector(标记-整理收集器)
标记整理收集器汲取了标记清除和复制收集器的优点,它分两个阶段执行,在第一个阶段,首先扫描所有活跃的对象,并标记所有活跃的对象,第二个阶段首先清除未标记的对象,然后将活跃的的对象复制到堆得底部。标记整理收集器的过程示意图请参考下图:
Mark-compact策略极大的减少了内存碎片,并且不需要像Copy Collector一样需要两倍的空间。
2.3 JVM的垃圾收集策略
GC的执行时要耗费一定的CPU资源和时间的,因此在JDK1.2以后,JVM引入了分代收集的策略,其中对新生代采用"Mark-Compact"策略,而对老生代采用了“Mark-Sweep"的策略。其中新生代的垃圾收集器命名为“minor gc”,老生代的GC命名为"Full Gc 或者Major GC".其中用System.gc()强制执行的是Full Gc.
2.3.1 Serial Collector
Serial Collector是指任何时刻都只有一个线程进行垃圾收集,这种策略有一个名字“stop the whole world",它需要停止整个应用的执行。这种类型的收集器适合于单CPU的机器。
Serial Copying Collector
此种GC用-XX:UseSerialGC选项配置,它只用于新生代对象的收集。1.5.0以后.
-XX:MaxTenuringThreshold来设置对象复制的次数。当eden空间不够的时候,GC会将eden的活跃对象和一个名叫From survivor空间中尚不够资格放入Old代的对象复制到另外一个名字叫To Survivor的空间。而此参数就是用来说明到底From survivor中的哪些对象不够资格,假如这个参数设置为31,那么也就是说只有对象复制31次以后才算是有资格的对象。
这里需要注意几个个问题:
Ø From Survivor和To survivor的角色是不断的变化的,同一时间只有一块空间处于使用状态,这个空间就叫做From Survivor区,当复制一次后角色就发生了变化。
Ø 如果复制的过程中发现To survivor空间已经满了,那么就直接复制到old generation.
Ø 比较大的对象也会直接复制到Old generation,在开发中,我们应该尽量避免这种情况的发生。
Serial Mark-Compact Collector
串行的标记-整理收集器是JDK5 update6之前默认的老生代的垃圾收集器,此收集使得内存碎片最少化,但是它需要暂停的时间比较长
2.3.2 Parallel Collector
Parallel Collector主要是为了应对多CPU,大数据量的环境。
Parallel Collector又可以分为以下两种:
Parallel Copying Collector
此种GC用-XX:UseParNewGC参数配置,它主要用于新生代的收集,此GC可以配合CMS一起使用。1.4.1以后
Parallel Mark-Compact Collector
此种GC用-XX:UseParallelOldGC参数配置,此GC主要用于老生代对象的收集。1.6.0
Parallel scavenging Collector
此种GC用-XX:UseParallelGC参数配置,它是对新生代对象的垃圾收集器,但是它不能和CMS配合使用,它适合于比较大新生代的情况,此收集器起始于jdk 1.4.0。它比较适合于对吞吐量高于暂停时间的场合。
Serial gc和Parallel gc可以用如下的图来表示:
2.3.3 Concurrent Collector
Concurrent Collector通过并行的方式进行垃圾收集,这样就减少了垃圾收集器收集一次的时间,这种GC在实时性要求高于吞吐量的时候比较有用。
此种GC可以用参数-XX:UseConcMarkSweepGC配置,此GC主要用于老生代和Perm代的收集。
参考资料
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
评论
这块有点糊涂。希望给解答一下。谢谢
请问是 哪三个啊? 我只看到有 2个 Virtual 还有 2个s
参见:http://java.sun.com/developer/technicalArticles/J2SE/monitoring/
再奉献些资料
http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html
http://blogs.sun.com/watt/resource/jvm-options-list.html
深入java 虚拟机上说的很明白了。。呵呵
呵呵,我是看了那本书以及网上的资源,总结了一下。
深入java 虚拟机上说的很明白了。。呵呵
兄弟,专家不敢当,离专家还远。
发表评论
-
Java高级软件攻城狮,你在哪里?
2013-09-17 11:19 0PS:管理员同志, ... -
Java高级软件攻城狮,你在哪里?
2013-09-17 09:46 5创业一年,感触颇多,也走过一些弯路,不过总体上还好。 ... -
Java高级软件攻城狮,你在哪里?我们需要你....
2013-09-06 13:43 88创业一年,感触颇 ... -
实例分析Java Class的文件结构
2013-01-30 11:11 5121今天把之前 ... -
Java自定义URL协议
2011-08-31 18:26 7017Java 提供了对 URL 协议进行扩展 ... -
JDK 1.6.0_13 Jaxb的一个Bug
2011-05-10 16:50 2329项目中使用jaxb进行xml binding,但是在jdk1. ... -
Apache+PHP+Mysql的搭建
2010-08-05 19:29 1618以前都是用JAVA,PHP没用过,今天因为一些原因,需 ... -
JVM内存模型以及垃圾收集策略解析【续】
2010-02-22 20:00 7362今天接着补全上篇博文 ... -
Java类加载器解析
2008-08-10 19:03 2241作者:狂放不羁 网址:http://yuquan-nana.i ... -
捕获checked exception后什么都不做的代价
2008-05-09 13:03 1728最近在做一个小项目,做到注册模块的时候,如果查询数据库后,发现 ... -
Three kinds of attributes in servlet
2008-03-02 00:21 1487There are three kinds of attrib ... -
My first Android programe!
2007-11-18 12:26 1385Today,i writed my first Android ... -
Java是剑客;.NET是刀客(转载)
2007-10-21 22:22 1466剑,一把好剑,重 ... -
高级语言发展简图
2007-09-30 15:35 1866C/C++语言谱系图 -
C#,C++ 与JAVA
2007-09-30 15:31 1715C#(C-Sharp)是Microsoft的新编程语言,被誉为 ... -
[转帖]利用Eclipse编辑中文资源文件
2007-09-09 03:57 4824如果经常使用Struts,并做过国际化操作的人来说,对于中文资 ... -
JAVA类加载器
2007-09-01 20:12 1723Java中加载器的种类大致可以分为四种:Bo ... -
JAVA类加载以及反射机制
2007-08-28 20:11 7407JAVA中类文件加载 ... -
小游戏
2007-08-28 16:48 1826偶前段时间写的小游戏。呵呵。。 -
今天起的早
2007-08-28 06:25 1272呵呵,今天早上很早就醒了。。记录一下这早起的早晨。
相关推荐
**JVM内存模型及垃圾收集策略解析** Java虚拟机(JVM)是Java程序运行的基础,它为Java程序提供了一个跨平台的运行环境。在深入理解JVM内存模型与垃圾收集策略之前,我们首先需要知道JVM的主要组成部分:类装载器、...
Java虚拟机(JVM)内存模型...理解JVM内存模型和垃圾回收机制对于优化Java应用性能、避免内存泄漏和有效利用资源至关重要。开发者应根据实际需求选择合适的垃圾回收器,并关注内存分配策略,以实现高效稳定的程序运行。
HotSpot VM在Java 5中引入了一系列自适应调优特性,能够在JVM启动时根据底层平台和系统配置自动选择合适的垃圾收集器、配置Java堆大小以及选择运行时JIT编译器。例如,在Server模式下,初始堆或堆的最小值(`-Xms`)...
JVM内存模型则是理解Java程序性能优化的关键,因为它规定了程序中的数据如何在内存中分配和访问。本文将深入浅出地探讨JVM内存模型,帮助你快速掌握这一核心概念。 首先,我们要知道JVM内存模型主要分为以下几个...
3. **JVM内存模型**: JVM内存主要分为堆内存(Heap)、栈内存(Stack)、方法区(Method Area)、程序计数器(PC Register)和本地方法栈(Native Method Stack)。重点理解对象创建、内存分配以及栈帧的工作方式...
新生代又细分为Eden区、From Survivor区和To Survivor区,用于垃圾收集策略。 2. 栈(Stack):每个线程都有一个独立的栈,用于存储方法调用时的局部变量、方法参数和返回地址。当方法执行完毕,栈帧会出栈。 3. ...
垃圾收集器会定期检查不再使用的对象并回收其占用的空间。 3. **垃圾回收** - **GC(Garbage Collection)**:Java的自动内存管理机制,负责清理无用对象,避免内存泄漏。 - **GC算法**:常见的有标记-清除、复制...
优化JVM内存配置是提升Java应用性能的重要手段,例如调整堆大小、新生代与老年代的比例、设置并发垃圾收集策略等。理解JVM的工作原理和内存模型,可以帮助我们更有效地诊断和解决内存相关的问题,比如内存溢出、内存...
- 堆内存分为新生代(Young Generation)和老年代(Tenured Generation),新生代又分为Eden区和两个Survivor区,用于实现高效的垃圾收集策略,如Minor GC和Major GC。 - 堆栈分离设计有助于提高系统性能,避免...
2. JVM内存模型:JVM内存分为五个区域:程序计数器、虚拟机栈、本地方法栈、Java堆和方法区。程序计数器记录当前线程执行的字节码指令地址;虚拟机栈和本地方法栈分别服务于Java方法和本地(Native)方法;Java堆是...
《JVM内存模型深度探索——基于JDK源码解析》 在Java开发中,深入理解JVM(Java Virtual Machine)内存模型是至关重要的。本文将从JDK源码的角度出发,详细探讨JVM的内存结构、类加载机制以及对象创建与内存分配...
### JVM内存模型详解 #### 1. 方法区 方法区主要存储类的信息、常量、静态变量等数据。这些数据通常在类加载时创建,并且在整个JVM生命周期中保持不变。对于HotSpot虚拟机而言,这部分区域被称为“永久代”(Perm...
【JDK 1.8 的 JVM 内存模型】 JVM(Java Virtual ...了解JVM内存模型和垃圾收集算法是Java开发者的基本功,对于实习生来说,掌握这些知识不仅能帮助应对面试,也能在实际开发中更好地理解和优化程序的内存使用。
总之,《深入理解JVM & G1 GC》这本书为读者提供了理解JVM内存模型和G1 GC的深入见解,有助于Java开发者更好地理解和控制JVM的内存管理,提升应用程序的稳定性和效率。通过学习这些知识,开发者可以解决实际开发中...
总结来说,从JVM入门到实战调优,涉及了Java程序从编译到执行的全过程,包括Class文件格式、类加载、内存模型、运行时数据区、垃圾收集策略以及调优实践等多个层面。深入理解和掌握这些知识,不仅有助于提升Java程序...
二、JVM内存模型 1. 堆(Heap):所有对象都在堆中分配内存,是线程共享的区域,分为新生代和老年代。 2. 新生代(Young Generation):新生代进一步划分为Eden区和两个Survivor区(From空间和To空间)。大部分对象...
5. **性能调优**:涵盖JVM性能监控工具的使用,如JConsole、VisualVM等,以及如何通过调整JVM参数(如-Xms, -Xmx, -XX:NewRatio等)来优化内存分配和垃圾收集策略。 6. **线程分析**:讲解如何理解和诊断线程问题,...
总结来说,基于Java虚拟机内存模型的性能调优涉及到多个层面,包括理解内存结构、垃圾回收机制、内存分配策略、调优工具的使用以及JVM参数的设置。通过深入理解和实践这些知识,开发者能够有效地优化Java应用程序,...
本文将深入探讨JVM的核心原理、内存结构、优化策略以及垃圾回收机制。 首先,JVM的内存结构是理解其工作方式的关键。在JVM中,内存主要分为五个区域:程序计数器、虚拟机栈、本地方法栈、堆和方法区(在Java 8之后...