project/jvm/JVM垃圾回收.md

4.3 KiB
Raw Permalink Blame History

参数描述

eden:s0:s1=8:1:1

https://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

  • -Xms start 起始大小
  • -Xmx max 最大大小
  • -Xmn new 新生代大小

多线程分配对象会出现指针碰撞(内存规整,同时初始化对象)

  • CAS 耗时,无法使用
  • TLAB Thread Local Allaction Buffer每个线程在栈上都有属于自己的一块单独的空间栈上分配。本地线程分配。逃逸分析对象超出方法使用范围。栈上分配快速为逃逸对象在栈上分配

内存分配,空间列表

  • Free List
  • Bump the pointer

进入老年代

大对象,新生代存储不下的对象,分配担保直接到老年代。

  1. 年龄超过15
  2. 相同年龄超过50%
  3. 动态年龄分配,不同年龄特别多。-XX:TargetSurvivorRatio 相同年龄所有对象的大小总和>Survivor空间的一半。
  4. 内存担保,新生代垃圾回收无法完成,直接放入老年代。 在GC前还会进行一次判断如果要分配的内存>=Eden区大小的一半那么会直接把要分配的内存放入老年代中。否则才会进入担保机制。-XX:+HandlePromotionFailure 检查老年代最大可用的连续空间是否大于历次晋升到老年代的平均大小。

TLAB的全称是Thread Local Allocation Buffer即线程本地分配缓存区这是一个线程专用的内存分配区域。

java -XX:+PrintCommandLineFlags -version

什么样的对象要被GC

判断回收算法

  • 引用计数法,相互引用,循环引用
  • 可达性分析GCroot本地变量表引用对象用来关联对象关系、方法区中的静态变量和常量虚拟机栈中本地变量表局部变量static成员常量引用本地方法栈中变量类加载器Thread
  • 不可达对象finalize可以挽回一次防止回收。
  • 本地方法栈中JNI引用的对象

GC范围

GC管理的主要区域是Java堆一般情况下只针对堆进行垃圾回收。方法区、栈和本地方法区不被GC所管理,因而选择这些区域内的对象的引用作为GC roots被GC roots引用的对象不被GC回收。

垃圾收集器

  • 并行parallel多个垃圾收集线程并行工作此时用户线程处于等待状态。
  • 并发concurrent用户线程和垃圾收集线程同时执行。
  • 吞吐量:用户代码执行时间/(用户代码执行时间+垃圾收集时间)

垃圾收集器算法

标记—清除算法Mark-SweepDVM 使用的算法)

标记—清除算法包括两个阶段:“标记”和“清除”。在标记阶段,确定所有要回收的对象,并做标记。清除阶段

紧随标记阶段,将标记阶段确定不可用的对象清除。标记—清除算法是基础的收集算法,标记和清除阶段的效率不高,

而且清除后回产生大量的不连续空间,这样当程序需要分配大内存对象时,可能无法找到足够的连续空间。

复制算法Copying

复制算法是把内存分成大小相等的两块,每次使用其中一块,当垃圾回收的时候,把存活的对象复制到另一块上,

然后把这块内存整个清理掉。复制算法实现简单,运行效率高,但是由于每次只能使用其中的一半,造成内存的利用率

不高。现在的 JVM 用复制方法收集新生代由于新生代中大部分对象98%)都是朝生夕死的,所以两块内存的比例

不是 1:1(大概是 8:1:1)。

标记—整理算法Mark-Compact

标记—整理算法和标记—清除算法一样,但是标记—整理算法不是把存活对象复制到另一块内存,而是把存活对象往内存的一端移动,然后直接回收边界以外的内存。标记—整理算法提高了内存的利用率,并且它适合在收集对象

存活时间较长的老年代。

分代收集Generational Collection

分代收集是根据对象的存活时间把内存分为新生代和老年代,根据各个代对象的存活特点,每个代采用不同的垃圾回收算法。新生代采用复制算法,老年代采用标记—整理算法。垃圾算法的实现涉及大量的程序细节,而且不同的虚拟机平台实现的方法也各不相同。