一.概述 

  • 哪些内存需要回收?
  • 什么时候回收?
  • 如何回收?

二.对象已死吗 

1.引用计数算法 

  1. 定义:给对象添加一个引用计数器,当增加一个引用时,加1,当一个引用时,减1;

  2. 缺陷:当对象之间互相循环引用时,就会变的像“不死对象”;

2.可达性分析算法

  在主流的商用程序语言(Java、C#,甚至包括前面提到的古老的Lisp)的主流实现中, 都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本思 路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所 走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连 (用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如 图3-1所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达 的,所以它们将会被判定为是可回收的对象

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

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

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

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

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

3、引用

  • 强引用:“=”实现,引用只要还在,就不会被GC回收;
  • 软引用:SoftReference实现,在内存不足发生OOM之期,就回收掉该引用;
  • 弱引用:WeakReference实现,在下一次GC前,就回收掉该引用;
  • 虚引用:PhantomReference实现,在任何时候可能被回收,不过回收后可以收到系统的通知;

4.生存还是死亡 (finalize方法自救)

  • 如果GC Roots 不可达,进行第一次标记;
  • 再看finalize()方法有没有被复写,有则先执行finalize()方法;
  1. 逃命方法:将自己关联到类变量之类或者某对象的成员变量的;
  2. 终身只有一次调用机会;
  • 接着GC进行第二次标记,如果没有逃脱,则回收;

5.无用的类

  • 所有该类的实例已被回收
  • 该类的ClassLoad已被回收
  • 该类对应的java.lang.Class没有在任何地方被引用,不存在该类的反射

三.垃圾回收算法

1、标记——清除法

  • 方案:先标记,然后直接回收
  • 缺陷:产生大量碎片,不好分配大内存

2、复制算法

  • 方案:将内存分为AB两块,回收时,将A块的对象全部复制到B,然后把未回收的上移,然后把已使用过的A全部清除;
  • 优点:实现简单,运行高效;
  • 缺陷:有一半处于无用状态,浪费;
  • HotSpot:通过 Eden:Surivor:Surivor=8:1:1的比例分配,这样只有10%的空间浪费;不足时,需要依赖其他内存分配担保;

3、标记—整理算法

  • 方案:标记—清理之后,再整体上移;
  • 适应:适合老年代内存区使用

4、分代收集算法

  • 新生代:使用复制算法
  • 老年代:使用“标记-清理”或者“标记—整理”算法

四.垃圾收集器

1、 Serial收集器

  • 这个收集器是一个单线程收集器,
  • 只会使用一个CPU或者一条收集线程进行垃圾收集工作
  • 其余的工作现场必须暂停,直到收集结束

2、ParNew收集器

  • Serial收集器的多线程版本
  • 垃圾收集器线程和工作线程同时工作

3、Paraller Scavenge收集器

  • 目标:达到一个可控的吞吐量
  • 吞吐量: 用户运行时间/(用户运行时间+垃圾回收时间)
  • GC自适应调节:调整参数提供最合适的停顿时间或者最大的吞吐量

4、CMS收集器

  • 目标:最短回收停顿时间
  • 步骤:
  1. 初始标记
  2. 并发标记
  3. 重新标记
  4. 并发清除
  • 缺点:
  1. 对CPU资源非常敏感
  2. 无法处理浮动垃圾
  3. 基于“标记-清除”算法实现,碎片多

5、G1 收集器

  • 并行与并发
  • 分代收集
  • 空间整合:
  1. 整体看:基于“标记-整理”算法
  2. 局部看:基于“复制”算法
  • 可预测停顿
  1. 有计划避免 Java 堆中进行全区域的垃圾收集

6、GC日志

33.125: [GC [DefNew: 3324k ->152k(3712k),0.0025925 secs] 3324k->152k(11904k),0.0031680 secs]
  • 33.125: GC发生时间
  • [GC:GC停顿类型,如果是 [Full GC
  • [DefNew: 垃圾回收器类型
  • 3324k ->152k(3712k): GC前内存区域已使用容量-> GC后内存区域已使用容量(内存区域总容量)
  • 3324k->152k(11904k): GC前Java堆已使用容量->GC后Java堆已使用容量
  • 0.0025925:内存区域GC所占用时间

五.内存分配和回收策略

最终都是给对象分配内存和回收分配给对象的内存

  • 对象优先在 Eden 分配
  • 大对象直接进入老年代
  • 长期存活的对象进入老年代
  • 动态对象年龄判定

如果在一个 Survivor 空间中相同年龄所占内存大小占有一半,那么大于或者等于该年龄的对象直接进入老年代

  • 空间分配担保

新生代的回收采用“复制算法”,如果没有足够的内存空间,需要老生代来担保,将一部分对象直接进入老年代,如果老年代空间还是不足,就有危险了。所以就根据以前进入老年代的对象容量大小的平均值来做个参考。通过 Fulll GC 对老年代进行一次GC,尽量腾出更多的空间。以防担保失败。

  • Minor Gc 和 Full GC
  1. Minor Gc:新生代的GC,很快
  2. Full GC:老年代的GC,慢10倍

六.小结

  本篇了解引用的算法,由此去判断一个对象是"死”还是“活”,四种引用类型,由强至弱,生存能力越来越差,被 GC 回收的可能性也就越高。当然在一生中有唯一一次的自救机会,就是复写 finalize() 方法。进行垃圾回收时,会影响到性能。所以,出了各种回收算法以及垃圾回收器。这些各有优劣,只有适合当前环境的才是最好的。

深入理解Java虚拟机03--垃圾收集器与内存分配策略的更多相关文章

  1. 深入理解Java虚拟机:垃圾收集器与内存分配策略

    目录 3.2 对象已死吗 判断一个对象是否可被回收 引用类型 finalize() 回收方法区 3.3. 垃圾收集算法 1.Mark-Sweep(标记-清除)算法 2.Copying(复制)算法 3. ...

  2. 《深入理解Java虚拟机》——垃圾收集器与内存分配策略

    GC需要完成: 哪些内存需要回收 什么时候回收 如何回收 如何确定对象不再使用 引用计数算法 给对象添加一个引用计数器,当有一个地方引用它时,计数器值进行加1操作:当引用失效时,计数器值进行减1操作: ...

  3. 深入理解Java虚拟机笔记——垃圾收集器与内存分配策略

    目录 判断对象是否死亡 引用计数器算法 可达性分析算法 各种引用 回收方法区 垃圾收集算法 标记-清除算法 复制算法 标记-整理算法 分代收集算法 HotSpot算法实现 枚举根节点 GC停顿(Sto ...

  4. 深入理解java虚拟机(3)垃圾收集器与内存分配策略

    一.根搜索算法: (1)定义:通过一系列名为"GC Roots"的对象作为起点,从这些起点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连的时 ...

  5. 深入JAVA虚拟机笔记-垃圾收集器与内存分配策略

    第三章:垃圾收集器与内存分配 问题:1.哪些内存需要回收 2.什么时候回收 3.怎么回收 回收方法区:

  6. java虚拟机(六)--垃圾收集器和内存分配策略

    目前没有完美的收集器,不同的厂商.版本的虚拟机提供的垃圾收集器会有很大的差别,用户根据自己应用特点和要求组合出各个年代所使用 的收集器.基于jdk1.7Update14之后的虚拟机. HotSpot的 ...

  7. 深入理解Java虚拟机之读书笔记三 内存分配策略

    一般的内存分配是指堆上的分配,但也可能经过JIT编译后被拆散为标量类型并间接地在栈上分配.对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配,少数情况下直接分 ...

  8. 深入理解java虚拟机----->垃圾收集器与内存分配策略(下)

    1.  前言 内存分配与回收策略 JVM堆的结构分析(新生代.老年代.永久代) 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保  2.  垃圾 ...

  9. 《深入理解Java虚拟机》(三)垃圾收集器与内存分配策略

    垃圾收集器与内存分配策略 详解 3.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第三章 ,为了整理思路,简单记录一下,方便后期查阅. 3.2 对象已死吗 在垃圾收集器进行回收 ...

  10. 《深入理解java虚拟机》第三章 垃圾收集器与内存分配策略

    第三章 垃圾收集器与内存分配策略 3.1 概述 哪些内存需要回收 何时回收 如何回收 程序计数器.虚拟机栈.本地方法栈3个区域随线程而生灭. java堆和方法区的内存需要回收.   3.2 对象已死吗 ...

随机推荐

  1. Spring面试底层原理的那些问题,你是不是真的懂Spring?

    1.什么是 Spring 框架?Spring 框架有哪些主要模块?Spring 框架是一个为 Java 应用程序的开发提供了综合.广泛的基础性支持的 Java 平台.Spring帮助开发者解决了开发中 ...

  2. linux的tar命令

    Linux下的tar压缩解压缩命令详解 tar -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中 ...

  3. Flex(ActionScript)与JavaScript交互的两种方式示例

    随着各单位部门信息化进程的不断发展,互通互联.共享协调不断的被越来越多的客户所重视.很多新项目都要去必须能够集成已有的早期系统,至少也要能够实现交互对接.今天跟大家分享的是系统对接中ActionScr ...

  4. ②泡茶看<数据结构>,喜欢看源码-栈ADT

    前言 听着天籁,我是个音乐迷.时间充实着,会过得很快.我马上也可以到傍晚的时候去乐室吹我心爱的萨克斯. 嘟嘟嘟... 我会吹一首简单的歌咯,哈哈我想到了一个神奇的比喻,待会说. 栈ADT模型(又称LI ...

  5. python练习四—简单的聊天软件

    python最强大的是什么?库支持!!有了强大的库支持,一个简单的聊天软件实现就更简单了,本项目思路如下 # 项目思路 1. 服务器的工作 * 初始化服务器 * 新建一个聊天房间 * 维护一个已链接用 ...

  6. 详谈js防抖和节流

    本文由小芭乐发表 0. 引入 首先举一个例子: 模拟在输入框输入后做ajax查询请求,没有加入防抖和节流的效果,这里附上完整可执行代码: <!DOCTYPE html> <html ...

  7. springboot情操陶冶-SpringApplication(二)

    承接前文springboot情操陶冶-SpringApplication(一),本文将对run()方法作下详细的解析 SpringApplication#run() main函数经常调用的run()方 ...

  8. MySQL系列详解六:MySQL主从复制/半同步演示-技术流ken

    前言 随着技术的发展,在实际的生产环境中,由单台MySQL数据库服务器不能满足实际的需求.此时数据库集群就很好的解决了这个问题了.采用MySQL分布式集群,能够搭建一个高并发.负载均衡的集群服务器.在 ...

  9. 前端(五)之display 总结与浮动

    前端之浮动布局.清浮动 display 总结 <!DOCTYPE html> <html> <head> <meta charset="UTF-8& ...

  10. mysql存储过程调用含out参数

    mysql 数据库有以下存储过程: CREATE DEFINER=`root`@`localhost` PROCEDURE `hovertreeTest`( IN `Param1` INT, ), O ...