美文网首页
Java基础->JVM垃圾回收

Java基础->JVM垃圾回收

作者: 杨0612 | 来源:发表于2020-10-20 15:30 被阅读0次

我们通常所说垃圾回收都是指堆内存的垃圾回收。

1.什么样的对象可以被回收呢?

与GC Root不存在任何直接或间接引用的对象都可以被回收。

以下对象可以作为GC Root

(1)静态对象;
(2)常量对象;
(3)存活的线程对象;
(4)局部变量表中的对象;

2.Java和Android GC时机

Java GC时机:
(1)虚拟机内存无法满足对象的创建;
(2)虚拟机内存到达某一个阀值;
(3)上层应用调用System.gc;
Android GC时机:
定义在art/runtime/gc/gc_cause.h文件中,大概只要关注以下三种即可;
(1)kGcCauseForAlloc,当分配内存失败,在尝试重新分配之前触发GC,这是会STW的;
(2)kGcCauseBackground,当分配内存成功以后,判断是否需要GC(考虑堆空间是使用率),即达到某个阀值,这种GC是处于后台的,不会STW;
(3)kGcCauseExplicit,显式调用System.gc;

Tips:对比Java和Android GC发现,GC时机大体差不多。
enum GcCause {
  // GC triggered by a failed allocation. Thread doing allocation is blocked waiting for GC before
  // retrying allocation.
  kGcCauseForAlloc,
  // A background GC trying to ensure there is free memory ahead of allocations.
  kGcCauseBackground,
  // An explicit System.gc() call.
  kGcCauseExplicit,
};
4.强引用、软引用、弱引用

(1)强引用,当该对象与GC Root存在强引用关系,那么虚拟机宁愿抛出OOM,也不会回收强引用;
(2)软引用,当该对象与GC Root只存在软引用关系,而且虚拟机处于内存不足的情况,则会被回收,注意被包裹的对象是回收了,软引用本身也是一个对象,是不会被回收的;
(3)弱引用,当该对象与GC Root只存在弱引用关系,被GC扫描到了就会被回收。

5.回收算法
5.1 标记清除

这个很好理解,先标记哪些需要回收,接着开始清除。
优点:实现简单;
缺点:容易产生内存碎片,内存浪费。

4.2 复制

将现有的内存区域划分为两块,暂且定义为A、B,A为当前使用的。
垃圾回收时,将A中可达的对象复制到B中,并清除A区域,完成后将B标记为当前使用的。
优点:实现简单,不会有内存碎片;
缺点:可用内存空间只有原来的一半;对象存活率高时,会被频繁的复制。

4.3 标记整理

标记可达对象,将其移动到内存的一端,清除边界以外的空间。
优点:防止了内存碎片产生,也不需要划分两块内存区域;
缺点:做压缩操作时,需要对对象进行移动,耗时。

5.分代策略

通常划分为新生代、老年代,不用区域采用不同的回收算法。
新生代与老年代之间按1/3,2/3的比例划分,这是参考数值,每个虚拟机都会有自己的设定。

5.1 新生代

(1)新创建的对象一般存放在新生代的。
(2)新生代的对象一般存活率很低,所以通常采用复制算法;
(3)新生代划分为Eden、S0、S1,按8:1:1大小来划分,这是参考数值,每个虚拟机都会有自己的设定。

Tips:大数据分析,90%的对象都会在第一次GC时被回收,仅存10%的对象,所以用10%的空间保存对象即可,而交换区的大小与10%一致,所以得到8:1:1的比例。
6.2 老年代

(1)对经过了多次回收(超过阈值)依然存活下来,将会被移到老年代;
(2)老年代的内存空间一般比新生代的大,当要创建大对象的时候,新生代经过GC以后依然没有足够的空间存放,将直接放入老年代。
(3)新创建对象是一个大对象,将直接进入老年代,所以尽量避免创建短周期的对象;
(4)老年代GC比新生代GC慢,因为老年代涉及到整理,以及操作对象较多;

6.对象分配空间过程

对象一般先在Eden区域分配空间,
(1)分配成功,直接返回;
(2)上述分配失败,则触发minor GC。Eden一般采用复制算法,将Eden可达对象复制到S0中,S1也进行赋值算法,将对象复制到S0中,清空Eden以及S1,分配成功,直接返回;
(3)上述分配失败,则触发FullGC。老年代一般采用标记整理算法,分配成功,直接返回;
(4)上述分配失败,则动态扩展内存空间;
(5)上述分配失败,则OOM。

8.思考题
1.OOM的根本原因

对于Android平台来说,系统对每个App申请的heap都是有限制的,一旦超过了限制的大小(Runtime.getRuntime().maxMemory())就会抛出OOM。即使在系统内存足够的情况,也会抛出异常。为什么会有这样的限制呢?移动设备的内存是有限的,那么App heap的申请就不能无限大,为了让更多的App可以常驻内存,提高响应速度,heap大小就要受到限制。

Tips:App OOM异常不是因为设备内存不足。设备内存不足时,系统会通过Memory kill来杀死一些优先级比较低的进程,保证优先级高的进程正常运行。
2.App为什么一开始不是得到最大可用内存呢?

(1)避免浪费,如果运行指令只需要10M,分配256M,就会有200多M的浪费;
(2)给GC增加难度,因为要处理的区域变大了,清理时间也变长了,卡顿也容易出现,容易产生碎片;

3.为什么内存使用很少的时候也会发生GC呢?

(1)没有足够空间分配给新对象,就会产生GC;
(2)即使有足够空间分配新对象,分配完以后也有可能发生GC,也就是达到某一个阀值产生GC,这是为了保证堆空间利用率。

以上分析有不对的地方,大家可以讨论下,互相学习哦!

相关文章

  • JVM垃圾回收算法

    Java基础:JVM垃圾回收算法 [toc] 参考:Java基础:JVM垃圾回收算法图解JVM垃圾回收算法 总结:...

  • 初步学习JVM底层原理(二)

    Java之JVM垃圾回收 内存结构以及垃圾回收算法 作为Java语言的核心之一,JVM垃圾回收帮我们解决了让我们很...

  • JVM垃圾回收机制

    JVM垃圾回收 整体思维导图 带着问题理解JVM垃圾回收机制 Java为什么需要垃圾回收机制; 回收哪部分垃圾; ...

  • Java工程师成神之路

    一、基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http:...

  • Java工程师成神之路

    一、基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http:...

  • 牛人

    一、基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http:...

  • Java学习之路

    一、基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http:...

  • 【收藏篇】Java工程师成神之路

    一、基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http:...

  • Java工程师成神之路~

    一、基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http:...

  • 面试-Java相关

    Java Java基础思想 Jvm相关 垃圾回收机制 多线程与进程 基础数据结构 基本设计模式 ClassLoader

网友评论

      本文标题:Java基础->JVM垃圾回收

      本文链接:https://www.haomeiwen.com/subject/ttfvxktx.html