Spring学习 - 自定义动态数据源 git进阶经验- git提交 log 的模板配置 Spring学习 - 自定义Spring 的 bean扫描器 Spring源码学习 - Scanner的工作原理 Spring源码学习 - bean的名称的生成方式 java源码学习之 Boolean 和 Byte 深入分析 Volatile 的实现原理 java各版本新特性 java源码学习之Short java源码学习之Integer 常见 MQ 的比较 - Kafka、RocketMQ、RabbitMQ的优劣势比较 Docker技术入门与实战 - 使用 dockerfile定制镜像 I love log 读书笔记 flink 入门程序-wordcount flink 配置项介绍 在 Mac 上搭建 Flink 的开发环境 lambda 架构问题的阅读笔记 IDEA常用插件 Mybatis源码分析(1) - Mybatis关键类 Mybatis源码分析(1) - Mybatis包目录简介 tair 1:tair学习 dataflow论文阅读笔记 Polysh的安装使用 SnappyData排序函数比较 Squirrel-sql客户端连接SnappyData手册 在虚拟机里显示Hello World spark学习博客推荐 SnappyData学习博客和官网文章 Docker常用命令 MyBatis支持的OGNL语法 mysql性能优化 mysql性能优化-优化Sql语句 mac上命令行操作 explain输出格式 从文件中读取zk配置——ZooKeeper编程技能(1) git进阶经验-从项目中删除移除的目录 Mongodb 学习之shell命令操作(3) mysql命令 git进阶经验-从多模块项目中分理子模块 从零学hadoop-搭建基础(单点)的Hdfs环境 ZooKeeper集群操作脚本 Vue安装使用 2 初学JVM之问答式记住类加载机制 2 初学JVM之问答式记住虚拟机性能监控与故障处理工具 2 初学JVM之问答式记住垃圾收集器 log4j2 按天生成日志文件 1 初学JVM之问答式记住java自动内存管理 MapReduce学习心得之MapReduce初识 log4j2 日志发送到kafka配置实战 log4j2 日志配置实战 Mongodb 学习之shell命令操作(二) Mongodb 学习之linux版本安装(一) Dubbo的初级使用 ServiceLoader内部实现分析 ServiceLoader 初级应用 log4j日志发送邮件配置实战 红黑树笔记 IDEA首次使用之前的配置 java源码学习之Enum java源码学习之String 自定义Spring tag标签 编写一键发布脚本 记一次Spring Scheduler莫名不执行的一次堆栈分析 kafka的基本操作 nginx 5:Nginx内部变量 nginx 4:Nginx日志管理 提高hadoop配置效率的shell脚本 Hive编程指南之一 Hive的安装 Ambari服务器安装 Ambari服务器管理集群 HBase分布式安装 windows下Eclipse远程调试运行MR程序 基于MapReduce新的API的编程Demo-wordCount window下Eclipse远程只读HDFS上的文件 YARN上节点标签 编写第一个MapReduce的wordcount程序 NodeManager的重启 搭建JStorm集群 YARN上的web应用代理 YARN上的ResourceManager的高可用方案 配置vmware中的虚拟机使用宿主机的共享网络 YARN架构简述 HDFS 架构 Spring的统一异常处理机制 Tomcat 配置服务 HDFS的viewfs指南 HDFS的Federation之路 HDFS基于QJM的HA之路 nginx 3:Nginx反向代理 mybatis操作主体流程 1.正则表达式学习-基础篇 log4j日志配置详解 mysql的时间函数 nginx 2:Nginx模块配置理论及实战 HashMap相关解析和测试文章 工作一年后的面试 用私有构造器或枚举类型强化Singleton属性 java中比较重要的图 mybatis处理枚举类 mybatis集成进spring Spring比较重要的几个截图 21.hadoop-2.7.2官网文档翻译-使用NFS的HDFS高可用性 20.hadoop-2.7.2官网文档翻译-使用仲裁日志管理器的HDFS高可用性 markdown在jekyll中支持的一些操作 Spring项目中配置sl4j和log4j的日志配置 19.hadoop-2.7.2官网文档翻译-HDFS命令指南 Spring的profile机制介绍 mybatis-generator反向生成 18.hadoop-2.7.2官网文档翻译-HDFS用户指南 17.hadoop-2.7.2官网文档翻译-实现Hadoop中Dapper-like追踪 16.hadoop-2.7.2官网文档翻译-Hadoop的KMS(key 管理服务器)-文档集 15.hadoop-2.7.2官网文档翻译-Hadoop的http web认证 14.hadoop-2.7.2官网文档翻译-服务级别的授权指南 13.hadoop-2.7.2官网文档翻译-安全模式中的Hadoop 09.hadoop-2.7.2官网文档翻译-Hadoop命令行微型集群 12.hadoop-2.7.2官网文档翻译-机架感知 11.hadoop-2.7.2官网文档翻译-代理用户-超级用户对其他用户的代表 10.hadoop-2.7.2官网文档翻译-原生库指南 08.hadoop-2.7.2官网文档翻译-文件系统规范 07.hadoop-2.7.2官网文档翻译-Hadoop接口类别 (转)浅析 Decorator 模式,兼谈 CDI Decorator 注解 06.hadoop-2.7.2官网文档翻译-Hadoop的兼容性 05.hadoop-2.7.2官网文档翻译-文件系统命令 04.hadoop-2.7.2官网文档翻译-Hadoop命令指南 03.hadoop-2.7.2官网文档翻译-集群安装 02.hadoop-2.7.2官网文档翻译-单节点集群安装 01.hadoop-2.7.2官网文档翻译-概述 Http 协议相应状态码大全及常用状态码 IDEA快捷键 JDBC Type与Java Type redis 12:redis 操作集合 mybatis-generator错误集合 redis 11:redis 错误集合 nginx 1:nginx的安装 redis 10:redis cluster命令操作 redis 9:redis实例集群安装 java设计模式 hadoop集群学习笔记(1) Apache Shiro 简介 vim编辑神器的进阶命令 Eclipse配置 Eclipse快捷键 Linux 测试题 Linux脚本学习(1) Linux启动简要过程 Centos7上安装Mysql hadoop集群学习笔记(1) (转)分布式发布订阅消息系统 Kafka 架构设计 maven 命令 Kafka集群安装 Kafka初步使用 redis 8:redis server 和 scripting命令操作 redis 7:redis transaction 和 connection命令操作 redis 6:redis hash 命令操作 redis 5:redis sorted_set 命令操作 搭建本地Jekyll+Markdown+Github的开发环境 Spring源码阅读笔记(2) redis 4:redis set命令操作 Spring添加任务调度配置 redis 3:Redis list命令操作 redis 2:redis 一般命令操作 redis 1:redis单机安装笔记 redis 0:redis配置属性描述 Spring源码阅读笔记(1) spark 错误集锦 spark集群安装 Linux 基本命令操作 Hadoop错误信息处理 Hadoop代码拾忆 从零开始搭建spring-springmvc-mybatis-mysql和dubbo项目 java知识点札记 java排错 Google Java Style 中文版 git进阶经验 github使用经验 MongoDB用户角色授权与AUTH启用 MongoDB 命令 MongoDB 特定规范 Spring MVC实现跳转的几种方式 史上最全最强SpringMVC详细示例实战教程 Spring 零星笔记 js中(function(){…})()立即执行函数写法理解 如何解决跨域问题 创建ajax简单过程 前端定位 设置MYSQL允许通过IP访问 mybatis异常 :元素内容必须由格式正确的字符数据或标记组成 如何为 WordPress 绑定多个域名的方法s WordPress工作原理之程序文件执行顺序(传说中的架构源码分析) Spring源码导入Eclipse中 基于PHPnow搭建Eclipse开发环境 解决wordpress首页文章内容截断处理的几种方法 ZooKeeper理论知识 ZooKeeper集群安装配置 Git常用命令速查表 Linux 4:磁盘与文件系统管理 Linux 3:文件与目录管理 Linux 2:文件权限与目录配置 Markdown输入LaTeX数学公式
从零学hadoop-搭建基础(单点)的Hdfs环境 MapReduce学习心得之MapReduce初识 Ambari服务器安装 Ambari服务器管理集群 windows下Eclipse远程调试运行MR程序 基于MapReduce新的API的编程Demo-wordCount window下Eclipse远程只读HDFS上的文件 YARN上节点标签 编写第一个MapReduce的wordcount程序 NodeManager的重启 YARN上的web应用代理 YARN上的ResourceManager的高可用方案 YARN架构简述 HDFS 架构 HDFS的viewfs指南 HDFS的Federation之路 HDFS基于QJM的HA之路 21.hadoop-2.7.2官网文档翻译-使用NFS的HDFS高可用性 20.hadoop-2.7.2官网文档翻译-使用仲裁日志管理器的HDFS高可用性 19.hadoop-2.7.2官网文档翻译-HDFS命令指南 18.hadoop-2.7.2官网文档翻译-HDFS用户指南 17.hadoop-2.7.2官网文档翻译-实现Hadoop中Dapper-like追踪 16.hadoop-2.7.2官网文档翻译-Hadoop的KMS(key 管理服务器)-文档集 15.hadoop-2.7.2官网文档翻译-Hadoop的http web认证 14.hadoop-2.7.2官网文档翻译-服务级别的授权指南 13.hadoop-2.7.2官网文档翻译-安全模式中的Hadoop 09.hadoop-2.7.2官网文档翻译-Hadoop命令行微型集群 12.hadoop-2.7.2官网文档翻译-机架感知 11.hadoop-2.7.2官网文档翻译-代理用户-超级用户对其他用户的代表 10.hadoop-2.7.2官网文档翻译-原生库指南 08.hadoop-2.7.2官网文档翻译-文件系统规范 07.hadoop-2.7.2官网文档翻译-Hadoop接口类别 06.hadoop-2.7.2官网文档翻译-Hadoop的兼容性 05.hadoop-2.7.2官网文档翻译-文件系统命令 04.hadoop-2.7.2官网文档翻译-Hadoop命令指南 03.hadoop-2.7.2官网文档翻译-集群安装 02.hadoop-2.7.2官网文档翻译-单节点集群安装 01.hadoop-2.7.2官网文档翻译-概述 hadoop集群学习笔记(1) hadoop集群学习笔记(1) Hadoop错误信息处理 Hadoop代码拾忆

2 初学JVM之问答式记住垃圾收集器

创建时间:2017年05月15日
摘要:

提问方式记住关键知识点

  1. 怎么判定对象是否存活

    判断对象是否存活,有以下几种判断方式:

    • 引用计数算法

      特点:实现简单,判断效率高
      应用方面:python、Squirrel、COM技术和flash palyer技术
      缺点:很难解决对象间循环引用问题。

    • 可达性分析算法

      应用方面:java、C#、Lisp等
      基本思路:以成为”GC Root”的对象作为起始点,向下搜索,所走过的路径称为引用链。而如果对象到”GC Root”不可达,就认为该对象不可用。

      可作为GC Roots的对象:虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象和本地方法栈中JNI引用的对象等四种

    另外:即使是可达性分析算法中的不可达对象,要被宣告死亡也至少需要两次标记过程。

  2. java中有哪些引用,分别解释下?

    在JDK1.2之后,java将引用扩充为四种:强引用、软引用、弱引用、虚引用。

    • 强引用

      类似使用User user = new User()方式的引用。只要强引用在,GC永远不会回收掉被引用的对象。

    • 软引用

      用来描述一些还有用但并非必需的对象。在系统将要发生内存溢出异常之前,这些对象会被二次回收。JDK1.2后的使用SoftReference实现软引用。

    • 弱引用

      描述非必需对象,比软引用更弱。被弱引用关联的对象只能生存到下次GC前。使用WeakReference实现弱引用。

    • 虚引用(幽灵引用、幻影引用)“

      为对象设置虚引用的唯一目的就是在对象被收集器收集时受到可以收到系统通知。JDK1.2之后提供了PhantomReference实现虚引用。

  3. 垃圾收集器会不会回收方法区,为什么?

    在JVM规范中不要求虚拟机堆方法区实现垃圾收集,而且性价比比较低(回收率低)。但方法区(HotSpot中的永久代)也可以进行垃圾回收,主要回收废弃常量和无用的类。

    在没有任何对象引用常量池中常量时,如果发生了回收,而且有必要的话,该常量就作为废弃常量清理出常量池。判断常量是否废弃比较简单,但判断类为无用类需要满足以下三种条件:

    • 该类所有的实例都被回收。

    • 加载该类的ClassLoader也被回收。

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

    满足条件不一定回收,可以使用-Xnoclassgc参数控制,也可以通过-verbose:class-XX:+TranceClassLoading-XX:+TranceClassUnLoading查看类加载和卸载信息。

  4. java中有哪些垃圾回收算法?

    • 标记-清除算法

      标记清除两阶段。先标记要回收的对象,然后在标记完后统一回收被标记的对象。

      定位:最基础的算法,其他算法都是对其的改进。

      不足:效率问题,标记清除效率都不高。空间问题,会产生大量内存碎片。

    • 复制算法

      原理:将可用内存分为相同的两块,每次只使用一块。当这一块用完了,就将存活的对象复制到另一块上,然后把已经使用过的内存清理掉。

      优点:不用关心内存碎片,实现简单,运行高效。 缺点:内存使用率低,不到总内存的一半;在对象存活率高的情况下,该方式效率低下。

      当前的商业虚拟机都是用该算法回收新生代,但比例就不是1:1了,而是将内存分为较大的Eden Space和两块较小的Survivor Space。HotSpot默认Eden和Survivor比例为8:1,也就是只浪费10%的内存。而当Survivor空间不足时,需要使用老年代进行分配担保。

    • 标记-整理算法

      标记过程与标记-清除算法一样,而后续是将存活的对象向一端移动,而在端界外的内存占用都清理掉。

    • 分代收集算法

      当前商用虚拟机都采用分代收集算法。

      思路:根据对象存活周期不同将内存分为几块(新生代、老年代),然后根据各代的特点选择最合适的收集算法。在新生代采用复制算法,因为每次收集有大量对象死去。在老年代次用标记-清除算法标记-整理算法

  5. HotSpot中的垃圾收集算法的实现?

    暂无

  6. 垃圾收集器有哪些?

    收集算法是内存回收的方法论,垃圾回收器是内存回收的具体实现。JVM中未规定垃圾回收器的实现。

    垃圾收集器的关系

    • Serial收集器

    • ParNew收集器

    • Parallel Scavenge收集器

    • Serial Old收集器

    • Parallel Old收集器

    • CMS收集器

    • G1收集器

  7. 什么是Serial收集器?

    • 定位:最基础,最悠久的收集器。jdk1.3之前的唯一选择。

    • 理论基础:使用复制算法的收集器

    • 特点:单线程收集器;在工作时必须暂停其他工作线程。

    • 外号:Stop the world

    • 存在的意义:仍然受运行在客户端模式下的虚拟机默认的新生代收集器,简单高效。因客户端模式虚拟机分配内存不会太大(几十兆到一两百兆),因此收集时间短,相对来说最合适。

  8. 什么是ParNew收集器?

    • 定位:Serial收集器的多线程版本。

    • 理论基础:使用复制算法的收集器

    • 缺点:单CPU下, ParNew收集器不会比Serial收集器表现好。

    • 存在的意义:运行在Server模式下虚拟机的首选新生代收集器,而且当前多线程中只有它能配合CMS一起工作。

  9. 什么是Parallel Scavenge收集器?

    • 定位:JDK1.4后出现的新生代收集器。独立实现,没有使用传统GC收集器框架。

    • 理论基础:使用复制算法的收集器

    • 目标:达到一个可控制的吞吐量(CPU运行用户代码时间/CPU总运行时间)

    • 应用:高吞吐量的收集器可以高效利用CPU的时间,主要适合在后台运算而不需要太多交互的任务。

    • 控制吞吐量参数:-XX:MaxGCPauseMillis(控制停顿时间)和-XX:GCTimeRatio(控制吞吐量大小)。

    • 外号:“吞吐量优先”收集器

    • 扩展:-XX:+UseAdaptiveSizePolicy参数设置后可以由虚拟机自动控制,动态调节参数。– GC自适应的调节策略。

  10. 什么是Serial Old收集器?

    • 定位:Serial收集器的老年代版本,也是单线程收集器。
    • 理论基础:使用标记-整理算法的收集器
    • 存在的意义:Client模式下的虚拟机使用。在Server模式下,主要有:1,与Parallel Scavenge搭配使用;2,作为CMS收集器的备用方案。在并发手机发生Concurrent Mode Failure时使用。
  11. 什么是Parallel Old收集器?

    • 定位:Parallel Scavenge收集器的老年代版本,诞生于JDk1.6,使用多线程和标记-整理算法

    • 理论基础:使用标记-整理算法的收集器。

    • 意义:使得Parallel Scavenge收集器终于有了合适的应用组合,在注重吞吐量及CPU资源敏感场合,可以优先考虑使用Parallel Scavenge+Parallel Old组合。

  12. 什么是CMS收集器?

    • 定位:JDK1.5之后推出,HotSpot上第一款真正意义上的并发收集器,实现了垃圾回收线程和用户线程同时工作。

    • 目标:获取最短回收停顿时间。

    • 应用:适合互联网站或者B/S系统的服务端,相应速度块,系统停顿时间短。

    • 理论基础:标记-清除算法

    • 运作过程:初始标记、并发标记、重新标记、并发清除四步骤。初始标记和重新标记仍然需要”Stop the world”,初始标记仅标记GCRoots能直接关联的对象,速度快。并发标记是进行GCRoots Tracing的过程。重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那部分对象的标记记录。停顿时间比初始标记稍长,但远比并发标记短。耗时最长的并发标记和并发清除可以与用户线程一起工作,所以总体看,CMS的内存回收是并发进行的。

    • 优点:并发收集、低停顿。

    • 缺点:

      • CMS收集器对CPU资源非常敏感。

      • CMS收集器无法处理浮动垃圾(在并发清除阶段产生的垃圾)。 需要预留内存空间提供并发收集时程序运行。

      • 基于标记-清除算法,收集结束后会有大量内存空间碎片产生。在无法存储大对象时触发Full GC。

      • 无法与Parallel Scavenge收集器配合使用。

  13. 什么是G1收集器?

    • 定位:面向服务端应用的垃圾收集器,未来替代CMS收集器。正式商用与JDK1.7_4

    • 特定:并行与并发;分代收集;空间整合(基于“标记-整理”算法,不会产生内存碎片);可预测的停顿。几乎就是实时java垃圾收集器。

    • 内存布局:与之前其他收集器不同,将整个java堆分为多个大小相等的独立区域,虽然保留了新生代和老生代概念,但不再是物理隔离,都是一部分Region的集合。

    难点:化整为零的思路,理解容易实现难。

    在G1中,Region间的对象引用及其他收集器中新生代和老生代间的对象引用,虚拟机使用RememberedSet避免全堆扫描。Region与RememberedSet为1对1关系。

    运作过程:初始标记、并发标记、最终标记、筛选回收。

  14. G1建立可预测的停顿时间模型的原因?

    因为G1收集器可以有计划的避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面垃圾堆积的价值大小 ,在后台维护优先列表。每次根据允许的收集时间,优先回收价值最大的Region。这种使用Region划分内存空间以及有优先级的区域回收方式,保证G1收集器在有限的时间内获取尽可能高的收集效率。

  15. G1执行内存回收的详细过程?

    初始标记节点仅仅只是标记下GCRoots能直接关联到的对象,并且修改TAMS(next top at mart start)的值,让下一阶段用户程序并发执行时,能在正确可用的Region中创建新对象,需要停顿线程,但耗时很短。

    并发标记阶段是从GC Roots开始对堆中的对象进行可达性分析,找出存活对象,耗时时间长但可与用户线程并行执行。

    最终标记阶段为了修正在并发标记期间因用户程序继续运作而导致标记产生变化的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remembered Set Logs中,在该阶段还需要将Remembered Set Logs中的数据合并到Remembered Set中。需要停顿线程,但可以并行执行。

    筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间指定回收计划。给阶段也可并发执行,但因为时间可控,停顿用户线程可提高收集效率。

  16. 垃圾收集器各参数列表

    垃圾收集器的关系2

  17. 内存分配与回收策略

    • 对象优先在Eden分配

      多数情况下,新生对象在新生代Eden区分配。当Eden没有足够空间时,将进行MinorGC。

      -XX:+PringGCGetails:参数打印内存回收日志。

    • 大对象直接进老年代

      大对象(需要大量连续分配内存空间的对象,如长字符串和数组),经常出现大对象容易导致内存还有空间时就会提前出发垃圾收集以获取连续空间。

      -XX:PretenureSizeThreshold令大于该设置阈值的对象直接进入老年代。避免在Eden和Survivor空间发生大量内存复制。

    • 长期存活的对象将进老年代

      虚拟机给每个对象定义对象年龄计数器,如果对象在Eden出生并经过一次MinorGC分配后仍然存活,将被移入到Survivor中,并且对象年龄置为1,每经过一次GC年龄加1,如果年龄达到设置阈值(默认为15),则晋升老年代。阈值可以通过-XX:MaxTenuringThreshold参数设置。

    • 动态对象年龄判定

      在Survivor空间中,如果相同年龄的所有对象大小总和大于Survivor空间一半,那将年龄更大或等于该年龄的对象直接进入老年代,不等待最大年龄阈值的触发。

    • 空间分配担保

    空间分配担保