JVM笔记
zhaolengquan Lv3

img

Java中99%的对象放在堆中,堆是垃圾回收主要操作区域。

新生代分为eden区,survivor1和survivor2区 比例是8:1:1

新生代的对象在经过15次GC之后进入老年代,大对象直接进入老年代。

绝大多数最新被创建的对象会分配到新生代,大部分对象在创建之后很快变得不可达,所以很多对象被创建在新生代,然后消失。对象从这个区域消失的过程我们称之为 minor GC。

老年代

对象没有变得不可达,并且从新生代中存活下来,会被拷贝到这里。其所占用的空间要比新生代多。也正由于其相对较大的空间,发生在老年代上的GC要比新生代少得多。对象从老年代中消失的过程,可以称之为major GC(或者full GC)。

永久代

垃圾回收机制

JVM垃圾回收机制

https://www.bilibili.com/video/BV1pZ4y197KK?p=9&spm_id_from=pageDriver

JVM内存中线程共享的是堆和本地方法区,

线程私有的是栈和程序计数器 栈又分为本地方法栈和虚拟机栈

GC

minorGC

minorgc 发生在年轻代

majorgc发生在老年代

JVM年轻代分为三个区域

  1. Eden
  2. Survivor(from)
  3. Survivor(to)

Eden和两个Survivor区 默认比例 8:1:1

为什么要分Eden和Survivor区,

因为新生代发生的gc比较频繁,如果不分Survivor区,那么Eden发生gc后 存活的对象直接被送到老年代,老年代会很快被填满. 而发生在老年代的Fgc消耗的时间要比ygc长的多.

设置两个Survivor区最大的好处就是减少了内存的碎片化

img

年轻代里的minorgc发生的特别频繁

新产生的对象大部分都放在Eden区

新建的对象都放在Eden区中,

第一次ygc

Eden区的大部分都会被回收 ->s0

第二次ygc

Eden区的和s0活着的对象->s1

第三次ygc

Eden区和s1活着的对象->s0

每次换区(s0->s1/s1->s0)

对象的年龄都会+1

多次垃圾回收后, 当对象的年龄到了,就会被放到老年代(Old区)

再后来, 老年代满了之后 会出发FullGC

对象分配规则

大对象直接分配到老年代,避免Eden区和Survivor区大量的内存拷贝

(动态年龄判断)

当Survivor区相同年龄的所有对象加起来大于Survivor区的一半 那么大于等于这个年龄的对象可以进入老年代

img

垃圾回收器

针对年轻代

  1. Serial 最基本的,发展历史最悠久的收集器工作环境是单线程, 收集器进行垃圾回收的时候,必须暂停其他所有的工作线程 (Stop The World)
    几十M /几M内存用Serial完全没问题如果内存很大, STW时间会特别长
  2. Parallel Scavenge
    并行清理垃圾(多线程) 并不是线程数越高效率越高 ,线程的上下文切换比较消耗资源
    并行收集::指多个垃圾回收器同时收集垃圾,此时业务逻辑线程暂停工作
  3. ParNew收集器 Serial收集器的多线程版本, 需要STW,使用的是复制算法
  4. CMS (concurrent mark sweep)
    并发垃圾回收用的是标记清除算法,会产生内存碎片
    这款收集器第一次实现了让垃圾收集线程与用户线程同时工作.
    CMS的关注点是尽可能缩短垃圾回收时,用户线程的停顿时间.停顿时间越短,越适合与用户交互的系统.
    JDK1.8以上 CMS建议升级为G1
  5. Serial Old收集器是Serial收集器的老年代版本, 主要针对老年代,
  6. Parallel Old收集器: 是Parallel Scavenge收集器的老年代版本,使用多线程,标记-整理算法。

常用垃圾回收算法

标记清除算法

标记到的垃圾可以直接回收,缺点就是内存碎片化,浪费空间

这里所谓的清除并不是真的置空,而是把需要清除的对象地址保存在空闲的地址列表里。下次有新对象需要加载时,判断垃圾的位置空间是否够,如果够,就存放。

缺点

需要扫描两遍,效率较低
GC的时候需要停止整个应用程序,用户体验感较差

这种方式清理出来的空闲内存是不连续的,产生内存碎片。需要维护一个空闲列表

拷贝算法(用在年轻代)

把一片内存分成大小相等的两块,每次只使用其中的一块,

当这一块的内存用完了,就把存活的对象复制到另外一块上面,然后把已使用的内存一次清理掉

优点是 保证了内存的连续可用

缺点是比较浪费空间(内存只能使用一半) 代价较高.

标记压缩

比标记清除多了一步整理,解决碎片化问题

整理压缩阶段,不是对标记的对象回收, 而是将存活的对象都向一端移动,然后擦除边界以外的内存

可以看到,标记的存活对象将会被整理,按照内存地址一次排列,而被标记的内存会被清理掉。如此一来,当我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可,这比维护一个空闲列表少开销多了

 Comments