java虚拟机中的内存管理、垃圾回收 GC要点

内存区域

java虚拟机中的内存管理、垃圾回收 GC要点

程序计数器:线程当前进行到哪一行指令的计数器

虚拟机栈: 局部变量存放处、即线程的方法内所需的变量等的信息空间

本地方法区:与虚拟机栈类似,但放的是本地Native方法服务

存放对象实例(划分了一片空间) 可分为新生代、老生代  或可分为Eden, From Survivor, To Survivor 用于回收

方法区:记录虚拟机已经加载了的数据   回收困难

运行时常量池:方法区的一部分,记录常量

直接内存:利用I/O直接用到的内存

 

垃圾回收

 

什么需要回收?

引用计数算法:引用+1,失效-1

可达性分析算法: 当一个对象到GC Roots没有任何引用链相连。

 

引用方式:

  1. 强引用:类似直接new,或者直接赋值
  2. 软引用:有用但非必须。 内存不够将会对这些引用列入回收范围进行第二次回收
  3. 弱引用:不论内存是否够,垃圾收集时都会被回收。
  4. 虚引用:对生存时间无影响,只在被回收时收到一个系统通知。

 

怎么回收?

 

垃圾收集算法:

  1. 标记-清除  效率不高,清理后内存变碎
  2. 标记-复制 老年代一般不用 方法:分为Eden From To 一次Eden From清理后复制放到To  一次Eden To 清理后复制放到From 15次后仍未清理进入老年代
  3. 标记-整理  清除后进行整理,使数据都向一段移动。
  4. 分代收集  新生代用标记-复制方法,老年代用标记整理方法

 

发起回收:(在何时进行GC)(方法和时间点选择)

  1. 枚举根节点:(用处:可达性分析方法的体现。判断是否有与GC Roots完全无连接的对象)
  2. Stop The World:枚举根节点时要保证停顿所有java执行线程。 原因是某一对象引用关系还在不断变化时则无法判断。
  3. 安全点:即每个线程到达安全点时才可以暂停。    原因是如果全部线程统一时间,则会因为OopMap产生大量额外空间。  安全点停止有两种方案:一是全部暂停,如不安全则继续跑至安全暂停(一般不用),二是设置一个标志每次经过判断是否需要停。
  4. 安全区域:即线程在这些区域都可以随时暂停。

垃圾收集器:

java虚拟机中的内存管理、垃圾回收 GC要点

新生代

  • Serial:单线程收集  简单而高效
  • ParNew:多线程版本 并且只有它能与CMS收集器配合工作
  • Parallel Scavenge 吞吐量优先,两个参数分别控制最大垃圾收集停顿时间和吞吐量大小

老年代

  • Serial Old: 单线程
  • Parallel Old:新生代选择Parallel Scavenge老年代只能选这个 注重吞吐量和CPU资源敏感时可用 并行
  • CMS

关键的两个收集器

CMS收集器

  • 基于“标记-清除算法”
  • 初始标记  并发标记  重新标记  并发清除  其中初始和重新两个操作需要stop the world
  • 缺点:对CPU非常敏感因为并发;无法处理浮动垃圾因为处理过程是并发的,且发生在stop的标记之后;会产生大量空间碎片 因为是标记清除方法 需要另进行整理操作,此时要停顿长时间

G1收集器

  • 能充分利用多CPU 缩短STW的过程 部分收集器停顿进行GC时,G1可并发的使Java程序继续运行
  • 内部分代收集
  • 区域价值优先 :特点是将java堆划分成大小相等的独立区域,跟踪每个区域的回收价值大小来确定优先回收哪个。
  • 初始标记(stop)  并发标记(并发)  最终标记(并行)  筛选回收(并行)

 

GC:分为Full GC,Major GC, Minor GC 

  • Minor GC(新生代GC):对象大多朝生夕灭,发生频繁,快
  • Major/Full GC(老年代GC):经常伴随一次Minor GC。一般会比Minor慢十倍

GC日志中的Full GC仅代表此次GC过程中出现了stop the world

 

内存分配和回收策略:给对象分配内存和回收分配给对象的内存

  • 对象优先在Eden分配  若Eden无空间先进行一次Minor GC
  • 大对象直接进入老年代(尽量避免短命的大对象“长的字符串、数组等”)
  • 长期存活的对象进入老年代
  • 进入老年代的对象年限动态判断(相同年龄总和大于一半设限、高于则进入老年代)
  • 检查老年代可用空间是否大于可能进入的对象平均大小,以此决定是否进行Full GC