`

JVM内存模型及垃圾回收机制

 
阅读更多

本文分两部分:

1.JVM内存结构(看图理解,不多讲)

2.垃圾回收机制

关于JVM的内存模型,本人整理了一张图仅供参考,有什么问题欢迎指正:



 

关于内存结构模型中的各个部分的具体功能在此就先不讲了(后期加补),各位可以先结合别的文章进行理解学习。

下面说下JVM垃圾回收机制:

1.哪些内存需要回收?

答:根据上图可知,JAVA内存运行时区域的各个部分,其中虚拟机栈、本地方法栈、程序计数器3个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着入栈和出栈的操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的(局部变量表存放了编译器可知的各种基本数据类型和对象引用),大体上可以认为是编译器可知的。因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多的考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了。而Java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存可能也不一样,我们只有在程序运行期间时才知道会创建哪些对象,这部分内存的分配和回收都是动态的,因此垃圾收集器所关注的主要是这部分内存。

2.什么时候回收?

答:在堆里面存放着Java中的几乎所有对象实例,垃圾收集器在对堆进行回收前,首先要确定这些对象之中哪些还“存活”,哪些已经“死去”(即不可能再被任何途径使用的对象)。

判断对象存活的算法包括两个:

2.1引用计数算法(Java虚拟机里没有选用)

算法原理是这样的:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1,任何时刻计数器为0的对象就是不可能再被使用的。

特点:引用计数算法(Reference Counting)的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软的COM(Component Object Model)技术。但是,至少主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要原因是它很难解决对象之间相互循环引用的问题。例如:对象ObjA和对象ObjB都有字段instance,赋值令objA.instance=objB及objB.instance=objA,除此之外这两个对象再无任何饮用,实际上这两个对象已经不可能再被引用了,但是他们因为相互引用者对方,导致他们的引用计数都不为0,于是引用计数算法无法通知GC收集器回收他们。

 

2.2可达性分析算法(Java虚拟机选用):

在主流的商用程序语言(Java、C#)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本原理就是通过一系列的称为“GC Roots”的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Root没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如图所示,对象object5、object6、object7虽然互相有关联,但是他们呢到达GC Roots是不可达的,所以他们将会被判定为是可回收的对象。

 在Java语言中,可作为GC Roots的对象包括下面几种:

虚拟机栈(栈帧中的本地变量表)中引用的对象。

方法区中类静态属性引用的对象。

方法区中常量引用的对象。

本地方法栈中JNI(即一般说的Native方法)引用的对象。

 

2.3回收方法区

很多人认为方法区是没有垃圾收集的,Java虚拟机规范中确实说过可以不要求虚拟机在方法区实现垃圾收集,而且在方法区中进行垃圾收集的“性价比”一般比较低:在堆中,尤其是在新生代中,常规应用进行一次垃圾收集一般可以回收70%~90%的空间,而永久代的垃圾收集效率远低于此。

       永久代的垃圾收集主要回收两部分内容:废弃常量和无用的类。以常量池中字面量的回收为例,加入一个字符串“abc”已经进入了常量池,但是当前系统中没有任何一个String对象是叫做“abc”的,换句话说就是没有任何String对象引用常量池中的“abc”常量,也没有其他地方引用了这个字面量,如果这时发生了内存回收,而且必要的话,这个“abc”常量就会被系统清理出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。

       判断一个类是否是无用的类需要同时满足下面3个条件才能算是“无用的类”:

       1)该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。

       2)加载该类的ClassLoader已经被回收。

       3)该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

 

 

3.如何进行回收?

3.1标记--清除算法

标记--清除(Mark-Sweep)算法是最基础的收集算法,算法氛围“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其不足进行改进而得到的。它的两个主要不足之处:一个是效率问题,标记和清除两个过程效率都不高;另一个是空间问题,标记和清除之后会产生大量不连续的内存碎片,空间碎片太多可能导致以后再程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。


 
 3.2复制算法 (用来回收新生代):   

         复制算法(Copying)是为了解决效率问题而出现的,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一般,未免太高了一点。

        现在的商业虚拟机都采用这种收集算法来回收新生代,IBM公司的专门研究表明,新生代中的对象98%是“朝生夕死”的,所以实际上并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的内存会被“浪费”。当然,98%的对象可回收只是一般情况下的数据,我们没办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion),也就是说如果另外一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象时,这些对象将直接通过分配担保机制进入老年代。



 

3.3标记--整理算法

      复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以老年代一般不能直接选用这种算法。

      根据老年代的特点,有人提出了“标记--整理”(Mark--Compact)算法,标记过程仍然与“标记--清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。



 

 

4.总结

       新生代中每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高,没有额外的空间对其进行分配担保,就必须使用“标记--清除”或者“标记--整理”算法来进行回收。

        补充一下内存分配与回收策略的相关知识:在大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC即小GC。大对象直接进入老年代,这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存复制。另外长期存活的对象将进入老年代,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1。对象在Survivor区中每“熬过”一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。对象年龄的阀值可以通过参数-XX:MaxTenuringThreshold=15来设置。然而,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Sruvivor空间中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等大最大阀值中要求的年龄。

  • 大小: 239.9 KB
  • 大小: 117.8 KB
  • 大小: 128.3 KB
  • 大小: 55.4 KB
  • 大小: 68.4 KB
分享到:
评论

相关推荐

    jvm内存模型以及垃圾回收机制.pptx

    jvm内存模型以及垃圾回收机制.pptx

    jvm内存模型以及垃圾回收机制.rar

    jvm内存模型以及垃圾回收机制详述

    jvm相关代码仓库,包括类加载机制,字节码执行机制,JVM内存模型,GC垃圾回收,JV-jvm_practice.zip

    jvm相关代码仓库,包括类加载机制,字节码执行机制,JVM内存模型,GC垃圾回收,JV-jvm_practice

    java垃圾回收以及jvm参数调优概述

    Java技术体系中所提倡的自动内存管理最终可以归结为自动化地解决了两个问题:给对象分配内存以及回收分配给对象...本文主要对java垃圾回收机制以及jvm参数等方面做个综述,也算是自己做开发这几年对这方面的一个总结。

    Java进阶教程解密JVM视频教程

    * 在垃圾回收章节,不仅会介绍垃圾回收算法、分代垃圾回收机制,还会重点介绍 G1 垃圾回收器,辨析 Full GC 发生条件,jdk8以来对垃圾回收的优化,以及垃圾回收的调优法则。 * 在字节码与类加载技术章节,会从一个 ...

    JVM详解及优化视频教程

    JVM详解及优化视频教程个人觉得讲的很不错所以分享。 主要章节内容: 1、jvm内存模型 2、垃圾回收算法、机制详解 3、JVM基本监控工具jstat、jstack、jconsole等的使用 4、JVM基本调优案例讲解

    Java集合、JVM面试题

    Java集合、JVM面试题,包括Java集合、JVM内存模型、垃圾回收机制、JVM调优、异常处理等相关面试题 适用于Java编程的初学者,加强自身对于Java集合、JVM、异常处理等方面的知识储备,更好的应对面试机会

    《JVM从入门到入魔》笔记.pdf

    1:JVM内存模型:类加载机制【转载、验证、准备、解析、初始化】+类装载器【装载器分类、加载原则】+运行时数据区【方法区、堆、虚拟机栈、本地方法栈、程序计数器】。 2:垃圾回收:垃圾确定【引用计数法、可达性分析...

    JVM虚拟机了解分享PPT

    JVM虚拟机分享,包括虚拟机发展、内存模型及垃圾回收机制介绍

    深入理解JVM内存结构及运行原理全套视频加资料.txt

    2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...

    深入理解Java虚拟机视频教程(jvm性能调优+内存模型+虚拟机原理)视频教程

    第34节垃圾回收-判断对象是否存活算法-可达性分析法详解00:07:09分钟 | 第35节垃圾回收算法-标记清除算法00:04:36分钟 | 第36节垃圾回收算法-复制算法00:14:35分钟 | 第37节垃圾回收算法-标记整理算法和分代收集...

    JVM思维导图(包含所有JVM知识)

    JVM整体结构内存模型(对象的创建,指针压缩,对象大小,对象内存),垃圾收集器,垃圾收集器算法、内存调优(调优工具),垃圾收集,内存回收(算法),类加载机制(类加载过程,双亲委派),一图学完JVM所有的知识...

    jMM+JVM-GC COLLECTOR+调优.pptx

    一个PPT包含 java内存模型,class运行机制。 java jvm垃圾回收算法 java jvm gc常见垃圾回收算法分析 java jvm调优

    JAVA超全面试突击包-答案讲义

    JVM:包括JVM的内存模型,垃圾回收机制,类加载,JVM调优。 多线程和高并发:包括JAVA的线程模型,同步机制,以及如何编写高并发程序。 设计模式:包括常见的设计模式,如单例模式,工厂模式,观察者模式等,以及...

    【Java面试+Java学习指南】一部分大部分Java招聘所需要掌握的核心知识

    JVM内存模型 性能调优、线上问题排查 类加载机制详解 垃圾回收机制 垃圾回收器、垃圾回收算法 ARM与多线程 多线程基础知识 常见关键字 多线程锁机制 线程池知识点 常见的JUC工具类 多线程经典面试题 常用工具集 ...

    Java学习指南,涵盖大部分Java程序员所需要掌握的核心知识

    JVM内存模型 性能调优、线上问题排查 类加载机制详解 垃圾回收机制 垃圾回收器、垃圾回收算法 并发与多线程 多线程基础知识 常见关键字 多线程锁机制 线程池知识点 常见的JUC工具类 多线程经典面试题 常用工具集 ...

    《剑指offer》JVM面试题总结.pdf

    聊一聊 JVM 中的垃圾回收算法? 标记-清除算法 标记-复制算法 标记-整理算法 什么是记忆集,什么是卡表?记忆集和卡表有什么关系? 什么是卡页? 什么是写屏障?写屏障带来的问题? 什么是三色标记法?三色标记法会...

    详解Android内存泄漏检测与MAT使用

    虽然JVM提供了自动垃圾回收机制,但是还是有很多情况会导致内存泄漏。 内存泄漏主要原因就是一个生命周期长的对象,持有了一个生命周期短的对象的引用。这样,会导致短的对象在该回收时候无法被回收。Android中...

    深入了解 JVM 虚拟机(超详细入门攻略)

    7. 简述 Java 垃圾回收机制8. 简述 Java 类加载机制9. 类加载器双亲委派模型机制10. 什么是类加载器,类加载器有哪些?11. 简述 java 内存分配与回收策率以及 Minor GC 和Major GC 1. 内存模型以及分区 JVM 分为堆区...

    Java面试题资料,包含核心知识,消息队列,大数据等

    这份资料不仅应该触及Java的基石——例如JVM的工作原理、内存模型、垃圾回收机制,以及Java的集合框架中的核心接口与实现类,如List、Set、Map等,更应对Java的异常处理机制有深入的剖析 此外,考虑到Java技术的...

Global site tag (gtag.js) - Google Analytics