前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java虚拟机--对象回收

Java虚拟机--对象回收

作者头像
SuperHeroes
发布2018-05-22 16:22:46
4220
发布2018-05-22 16:22:46
举报
文章被收录于专栏:云霄雨霁云霄雨霁

上一篇:Java虚拟机--Java堆中对象的创建和布局

哪些内存需要回收?

程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,随线程而灭,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收问题,因为方法结束或线程结束时,内存自然就跟着回收了。而Java堆方法区则不一样:一个接口的多个实现类需要的内存可能不一样,一个方法中多个分支需要的内存也可能不一样,只有在程序处于运行时才会知道要创建哪些对象,这部分内存的分配和回收都是动态的,垃圾回收器关注的是这部分内存。

怎么判断一个对象要被回收?

引用计数法

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

引用计数法实现简单,判定效率也很高,在大部分情况下是一个不错的算法。但主流的Java虚拟机都没有使用引用计数法来管理内存,其中主要的原因是:它很难解决对象之间互相引用的问题。

可达性分析法

通过一系列的称为“GC Roots"的对象作为起点,从这些起点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(图论中的不可达)时,则证明该对象是不可用的。主流实现都是使用可达性分析实现判断对象是否存活的。

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

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象;
  • 方法区中类静态属性引用的对象;
  • 方法区中常量引用的对象;
  • 本地方法栈中Native方法引用的对象。

引用:

上面两种方法都与”引用“有关,Java中引用分为四种:强引用、软引用、弱引用和虚引用。

  • 强引用:只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。
  • 软引用:软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。
  • 弱引用:弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
  • 虚引用:最弱的一种引用关系。一个对象是否有需引用的存在完全不会对其生存时间构成影响,也无法通过需引用来取得一个对象实例。为一个对象设置一个需引用的唯一目的就是能够在这个对象被收集器回收时收到一个系统通知。

回收方法区:

方法区可以不实现垃圾收集,但也可以进行垃圾收集。永久代(方法区)的垃圾收集主要回收两方面的内容:废弃常量无用的类。回收废弃常量和回收Java堆中的对象非常类似。

判断一个废弃常量非常容易但判断一个类是”无用的类“则苛刻得多,必须满足下面三个条件:

  1. 该类的所有实例都被回收,也就是Java堆中不存在该类的任何实例;
  2. 加载该类的ClassLoader已经被回收;
  3. 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

内存分配与回收策略

Java的自动化内存管理最终可以归结为解决两个问题:给对象分配内存和回收分配给对象的内存。

对象的内存分配,往大的方向说就是在堆上分配,对象主要分配在新生代的Eden区上,如果启用了本地线程分配缓冲,将按线程优先在TLAB上分配,少数情况下也直接在老年代中分配。下面是一些最普遍的内存分配原则:

1、对象优先在Eden分配

大多数情况下对象在新生代 Eden区分配,如果Eden区没有足够空间进行分配,虚拟机将会发起一次Minor GC。

  • 新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java对象大多具有朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度比较快。
  • 老年代GC(Major GC / Full GC):指发生在年老代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(但并非绝对)。Major GC一般比Minor GC慢10倍以上。
2、大对象直接进入老年代

所谓的大对象是指,需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组。大对象对内存分配来说是一个坏消息(更坏的消息是”朝生夕灭“的大对象,编程中应该尽量避免),经常出现的大对象容易导致内存还有不少空间时就要触发急啊急手机以获取足够的空间。

3、长期存活的对象将进入老年代

虚拟机给每个对象定义了一个对象年龄计数器。如果对象在经历过第一一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor中,并且对象年龄加一。对象在Survivor中每熬过一次Minor GC就让年龄加一。当年龄增加到一定程度(默认为15),就会被晋升到年老代中。

4、动态对象年龄判定

为了适应不同情况,虚拟机并不永远要求对象年龄达到指定的数值才晋升到年老代。如果在Survivor空间中相同年龄的所有对象综合大于Survivor空间的一半,那么大于等于该年龄的对象都要直接进入老年代。

下一篇:Java虚拟机--垃圾收集算法和垃圾收集器

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 上一篇:Java虚拟机--Java堆中对象的创建和布局
  • 哪些内存需要回收?
  • 怎么判断一个对象要被回收?
    • 引用计数法
      • 可达性分析法
      • 引用:
      • 回收方法区:
      • 内存分配与回收策略
        • 1、对象优先在Eden分配
          • 2、大对象直接进入老年代
            • 3、长期存活的对象将进入老年代
              • 4、动态对象年龄判定
              • 下一篇:Java虚拟机--垃圾收集算法和垃圾收集器
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档