收藏 分享(赏)

jvm内存模型以及垃圾收集策略解析.doc

上传人:cjc2202537 文档编号:1318941 上传时间:2018-06-23 格式:DOC 页数:13 大小:320KB
下载 相关 举报
jvm内存模型以及垃圾收集策略解析.doc_第1页
第1页 / 共13页
jvm内存模型以及垃圾收集策略解析.doc_第2页
第2页 / 共13页
jvm内存模型以及垃圾收集策略解析.doc_第3页
第3页 / 共13页
jvm内存模型以及垃圾收集策略解析.doc_第4页
第4页 / 共13页
jvm内存模型以及垃圾收集策略解析.doc_第5页
第5页 / 共13页
点击查看更多>>
资源描述

1、一 JVM 内存模型 1.1 Java 栈 Java 栈是与每一个线程关 联的,JVM 在创建每一个线程的时候,会分配一定的栈空间给线程。它主要用来存储线程执行过程中的局部变量,方法的返回值,以及方法调用上下文。栈空 间随着线程的终止而释放。StackOverflowError:如果在线程执行的过程中, 栈空间不够用,那么 JVM 就会抛出此异常,这种情况一般是死递归造成的。1.2 堆 Java 中堆是由所有的线程共享的一 块内存区域,堆用来保存各种 JAVA 对象,比如数组,线程对象等。1.2.1 Generation JVM 堆一般又可以分为以下三部分:PermPerm 代主要保存 cla

2、ss,method,filed 对象,这部门的空间一般不会溢出,除非一次性加载了很多的类,不 过在涉及到热部署的应用服务器的时候,有时候会遇到 java.lang.OutOfMemoryError : PermGen space 的 错误,造成 这个错误的很大原因就有可能是每次都重新部署,但是重新部署后,类 的 class 没有被卸载掉,这样就造成了大量的 class 对象保存在了 perm 中, 这种情况下,一般重新启动应用服务器可以解决问题。TenuredTenured 区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在 Young 复制转移一定的次数以后, 对象就会被转 移到

3、Tenured 区,一般如果系统中用了 application 级别 的缓存, 缓存中的对象往往会被 转移到这一区间。YoungYoung 区被划分为三部分, Eden 区和两个大小严格相同的 Survivor 区,其中Survivor 区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在 Young 区 间变满的时候, minor GC 就会将存活的对象移到空闲的 Survivor 区间中,根据 JVM 的策略,在经过几次垃圾收集后,任然存活于Survivor 的对象将被移动到 Tenured 区间。1.2.2 Sizing the Generations JVM 提

4、供了相应的参数来对内存大小进行配置。正如上面描述,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,

5、这样 eden+2*survivor=1/9堆内存-XX:SurvivorRatio=32 意味着 eden 和一个 survivor 的比值是 32:1,这样一个Survivor 就占 Young 区的 1/34.-Xmn 参数 设置了年轻代的大小Perm Generation-XX:PermSize=16M -XX:MaxPermSize=64MThread Stack-XX:Xss=128K1.3 堆栈分离的好处 呵 呵,其它的先不说了,就来说说面向对象的设计吧,当然除了面向 对象的设计带来的维护性,复用性和扩展性方面的好处外,我们看看面向对象如何巧妙的利用了堆 栈分离。如果从 JAVA

6、 内存模型的角度去理解面向对象的设计,我们就会发现对象它完美的表示了堆和栈,对象的数据放在堆中,而我们编写的那些方法一般都是 运行在栈中,因此面向对象的设计是一种非常完美的设计方式,它完美的统一了数据存储和运行。二 JAVA 垃圾收集器 2.1 垃圾收集简史 垃圾收集提供了内存管理的机制,使得应用程序不需要在关注内存如何释放,内存用完后,垃圾收集会进 行收集, 这样就减轻了因 为人为的管理内存而造成的错误,比如在 C+语言里,出现内存泄露时很常见 的。Java 语言是目前使用最多的依 赖于垃圾收集器的语 言,但是垃圾收集器策略从 20 世纪 60 年代就已经流行起来了,比如 Smalltalk

7、,Eiffel 等编程语言也集成了垃圾收集器的机制。2.2 常见的垃圾收集策略 所有的垃圾收集算法都面临同一个问题,那就是找出应用程序不可到达的内存块,将其释放,这里面得不可到达主要是指应用程序已经没有内存块的引用了,而在 JAVA 中,某个对象 对应用程序是可到达的是指:这个对象被根(根主要是指类的静态变量,或者活跃 在所有线程栈的对象的引用)引用或者对象被另一个可到达的对象引用。2.2.1 Reference Counting(引用计数) 引用计数是最简单直接的一种方式,这种方式在每一个对象中增加一个引用的计数,这个计数代表当前程序有多少个引用引用了此对象,如果此对象的引用计数变为 0,那

8、么此对象就可以作为垃圾收集器的目标对象来收集。优点:简单,直接,不需要暂停整个应用缺点:1.需要编译器的配合,编译器要生成特殊的指令来进行引用计数的操作,比如每次将对象赋值给新的引用,或者者对象的引用超出了作用域等。2.不能处理循环引用的问题2.2.2 跟踪收集器 跟踪收集器首先要暂停整个应用程序,然后开始从根对象扫描整个堆,判断扫描的对象是否有对象引用,这里面有三个问题需要搞清楚:1如果每次扫描整个堆,那么势必让 GC 的时间变长,从而影响了应用本身的执行。因此在 JVM 里面采用了分代收集,在新生代收集的时候 minor gc 只需要扫描新生代,而不需要扫 描老生代。2JVM 采用了分代收

9、集以后,minor gc 只扫描新生代,但是 minor gc 怎么判断是否有老生代的对象引用了新生代的对象,JVM 采用了卡片标记的策略,卡片标记将老生代分成了一块一块的,划分以后的每一个块就叫做一个卡片,JVM采用卡表维护了每一个块的状态,当 JAVA 程序运行的时候,如果发现老生代对象引用或者释放了新生代对象的引用,那么就 JVM 就将卡表的状态设置为脏状态,这样 每次 minor gc 的时候就会只扫描被标记为脏 状态的卡片,而不需要扫描整个堆。具体如下图:3GC 在收集一个对象的时候会判断是否有引用指向 对象,在 JAVA 中的引用主要有四种:Strong reference,Sof

10、t 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软引用的对象在

11、GC 的时候不会被回收,只有当内存不 够用的时候才会真正的回收,因此软引用适合缓 存的场合, 这样使得缓存中的对象可以尽量的再内存中待长久一点。Public void testSoftReference()String str = “test“;SoftReference softreference = new SoftReference(str);str=null;System.gc();assertNotNull(softreference.get();Weak reference弱引用有利于对象更快的被回收,假如一个对象没有强引用只有弱引用,那么在 GC 后,这个对象肯定会被回收。Pub

12、lic void testWeakReference()String str = “test“;WeakReference weakReference = new WeakReference(str);str=null;System.gc();assertNull(weakReference.get();Phantom reference 2.2.2.1 Mark-Sweep Collector(标记-清除收集器) 标记清除收集器最早由 Lisp 的发明人于 1960 年提出,标记清除收集器停止所有的工作,从根扫描每个活跃的对象,然后 标记扫 描过的对象, 标记完成以后,清除那些没有被标记的对

13、象。优点:1 解决循环引用的问题2 不需要编译器的配合,从而就不执行额外的指令缺点:1每个活跃的对象都要进行扫描,收集暂停的时间比较长。2.2.2.2 Copying Collector(复制收集器) 复制收集器将内存分为两块一样大小空间,某一个时刻,只有一个空间处于活跃的状态,当活跃的空间满的时候, GC 就会将活跃的对象复制到未使用的空间中去,原来不活跃的空间 就变为了活跃的空间。复制收集器具体过程可以参考下图:优点:1 只扫描可以到达的对象,不需要扫描所有的对象,从而减少了应用暂停的时间缺点:1需要额外的空间消耗,某一个时刻, 总是有一块内存处于未使用状态2复制对象需要一定的开销2.2.

14、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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 经营企划

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报