zoukankan      html  css  js  c++  java
  • JAVA复习笔记之GC部分

        前言:垃圾回收机制,大家都知道JAVA的垃圾回收都是JVM自动回收的,不需要程序员去管理。但是我们还是得知道原理才能在适当时机进行JVM调优

      原理:当我们new 一个对象时JVM堆区就会分配一块内存(地址,大小)给这个对象,当这个对象“不可达”的时候(即程序无法访问的时候),GC就需要回收这块空间。

      Java语言规范没有明确地说明JVM使用哪种垃圾回收算法,但是任何一种垃圾回收算法一般要做2件基本的事情:(1)发现无用信息对象;(2)回收被无用对象占用的内存空间,使该空间可被程序再次         使用,

      算法包括:

      1. 引用计数(Reference Counting):给每个对象添加一引用计数器,每当有一个地方引用它的时候,计数器+1;引用失效的时候,计数器-1

      2.可达性分析算法(Rearchability Analysis):通过一系列的“GC roots”的对象作为起点,从这些节点向下搜索,搜索所超过的路径称为引用链,当一个对象到GC roots没有任何引用链相连的时候则此对         象是不可用的,不可用的对象则是JVM判定为可回收的对象。目前Java中可以作为GC ROOT的对象有:

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

                        2、方法区中静态属性引用的对象

                        3、方法区中常亮引用的对象

                        4、本地方法栈中引用的对象(Native对象)

      

      3. 标记-清除(Mark-Sweep):从引用的根节点开始标记所有引用的对象,遍历整个堆内存,把未标记的对象清楚(老年代)

       4. 复制(Copying):把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中(年轻代)

       5. 标记-整理(Mark-Compact :第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象 “压缩”到堆的其中一块,按顺序排放(老年代)

      6. 分代(Generational Collecting 

      首先我们得先清除JVM堆内存的结构(如下图),可以看到一共有3个区域:年轻代(Young Generation)、老年代(Old Generation)、永久代(Permanent Generation,也就是方法区)

      

          年轻代(Young Generation)

      包括一个Eden区和2个Survivor 区(From 和 to  ),绝大多数的对象刚创建时都被分配在Eden区(Eden区是连续的内存空间,因此在其上分配内存极快),当第一次Eden区空间满了的时候进行第一            次Minor GC:回收掉“消亡”的对象,存活的对象复制到From内存 中(To内存此时是空的),Eden区域为空;下次Eden满的时候,又会触发Minor GC,回收掉消亡对象,存活的对象还是复制到From内存          中,当From内存满了的时候,GC会把From中还存活的对象复制到To内存中吗,清空From,这就确保了From和To永远至少有一个区是空的;重复以上步骤依然存活的对象会被默认放到老年代中。在年轻          代发生的GC只有Minor GC,发生的频率比较高(不一定是Eden满的时候)

         老年代(Old Generation)

           存放经历N次Minor GC依然存活的对象,当老年代的内存空间满的时候会触发Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高

         永久代(Permanent Generation也就是方法区

         用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运         行过程中新增的类

      总结的一些常见问题:

      Q:JVM GC回收哪个区域内的垃圾?

       JVM GC只回收堆区和方法区内的对象。而栈区的数据,在超出作用域后会被JVM自动释放掉,所以其不在JVM GC的管理范围内

     Q:JVM GC怎么判断对象可以被回收了?

         对象没有引用

         作用域发生未捕获异常

         程序在作用域正常执行完毕

         程序执行了System.exit()

         程序发生意外终止(被杀线程等)

       PS:上面那个是网上的答案,我个人觉得应该回答从GC root搜索不到,而且经过第一次标记、清理后,仍然没有复活的对象被回收更加合理

     Q:GC策略都有哪些分类?

       引用计数:难解决对象之间相互引用的问题

       可达性分析算法:基本所有GC算法都引用根搜索算法这种概念

       标记-清除 :会有内存碎片

     复制:是对象的存活率非常低

        标记-整理(Mark-Compact)缺点:成本大

       JVM为了优化内存的回收,使用了分代回收的方式,对于新生代内存的回收(Minor GC)主要采用复制算法。而对于老年代的回收(Major GC),大多采用标记-整理算法 

      Q:什么时候一个对象会被GC ?

     把minor GC和Full GC介绍下即可

      Q:如果老年代的对象需要引用新生代的对象,会发生什么呢?

       为了解决这个问题,老年代中存在一个 card table ,它是一个512byte大小的块。所有老年代的对象指向新生代对象的引用都会被记录在这个表中。当针对新生代执行GC的时候,只需要查询 card table 来决     定是否可以被回收,而不用查询整个老年代。这个 card table 由一个write barrier 来管理。write barrier给GC带来了很大的性能提升,虽然由此可能带来一些开销,但完全是值得的。

     总结:其实GC只要了解了三个问题就行 “什么时候”,“对什么东西”,‘“做了什么”

      

  • 相关阅读:
    [转]tensorflow提示:No module named ''tensorflow.python.eager"
    mac使用pip3安装tensorflow(不用conda)
    不限速、没广告的迅雷(旧版迅雷)
    python从国内镜像安装第三方库
    Jupyter 安装并配置工作路径[转]
    VS2013只显示会附加到进程,无法启动调试
    电脑磁盘空间占用高于文件夹大小
    Latex基础
    C#/.Net 部分缩写
    texstudio设置外部浏览器及右侧预览不能使用问题
  • 原文地址:https://www.cnblogs.com/zwt1990/p/8322376.html
Copyright © 2011-2022 走看看