JVM复习知识点,有空会完善前面的内容。重点是类加载和new对象的过程,以及对新生代老年代以及eden区的思考。

JVM内存模型


内存各区域作用


标记清除算法


复制算法


标记整理


可达性算法


可达性算法的GC roots

  • 虚拟机栈中引用的对象
  • 本地方法栈中引用的对象
  • 方法区常量池中的常量
  • 方法区静态成员引用的对象

G1


堆的划分
默认比例
新生代:老年代 = 1:2
新生代中分eden区和两个survivor,比例8:1:1


新生代老年代的比例思考

web应用中的对象基本可以分成这三种。
( a) 有一部分对象几乎一直活着。这些可能是常用数据的cache之类的
( b) 有一部分对象创建出来没多久之后就没用了。这些很可能会响应一个请求时创建出来的临时对象
( c) 最后可能还有一些中间的对象,创建出来之后不会马上就死,但也不会一直活着。

新生代快满的时候会触发young GC/minor GC,老年代快满会出发full GC,调整分区比例就是分配大小,越小的内存,其对应的GC频率就会高。

  • 新生代比例过大,老年代比例小
    比例太大的话,会导致minor GC频率太低,一些我们希望进入老年代的对象一直不能进入老年代。新生代太大,那么每次minorGC的时长太久,并且因为老年代内存小,会经常触发fullGC(会清理新生代和老年代),这样就会导致频繁的Stop-The-Word,且时间很长。
  • 老年代比例过大,新生代比例小
    新生代比例小,minorGC频率高,虽然每次的时间会很短,但可能有些我们不想它进老年代的也进了老年代。还有可能有些临时对象刚创建还没使用就被回收了。

survivor的思考

  • 为什么要有survivor
    我们看看如果没有 Survivor 空间的话,垃圾收集将会怎样进行:一遍新生代 gc 过后,不管三七二十一,活着的对象全部进入老年代,即便它在接下来的几次 gc 过程中极有可能被回收掉。这样的话老年代很快被填满, Full GC 的频率大大增加。我们知道,老年代一般都会被规划成比新生代大很多,对它进行垃圾收集会消耗比较长的时间;如果收集的频率又很快的话,那就更糟糕了。基于这种考虑,虚拟机引进了“幸存区”的概念:如果对象在某次新生代 gc 之后任然存活,让它暂时进入幸存区;以后每熬过一次 gc ,让对象的年龄+1,直到其年龄达到某个设定的值(比如15岁), JVM 认为它很有可能是个“老不死的”对象,再呆在幸存区没有必要(而且老是在两个幸存区之间反复地复制也需要消耗资源),才会把它转移到老年代。

总之,设置 Survivor 空间的目的是让那些中等寿命的对象尽量在 Minor GC 时被干掉,最终在总体上减少虚拟机的垃圾收集过程对用户程序的影响。

  • 为什么要有两个survivor
    我们来看看在只有一个 Survivor 空间的情况下,这个 8:1 会有什么问题。此处为了方便说明,我们假设新生代一共为 9 MB 。对象优先在 Eden 区分配,当 Eden 空间满 8 MB 时,触发第一次 Minor GC 。比如说有 0.5 MB 的对象存活,那这 0.5 MB 的对象将由 Eden 区向 Survivor 区复制。这次 Minor GC 过后, Eden 区被清理干净, Survivor 区被占用了 0.5 MB ,还剩 0.5 MB 。到这里一切都很美好,但问题马上就来了:从现在开始所有对象将会在这剩下的 0.5 MB 的空间上被分配,很快就会发现空间不足,于是只好触发下一次 Minor GC 。可以看出在这种情况下,当 Survivor 空间作为对象“出生地”的时候,很容易触发 Minor GC ,这种 8:1 的不对称分配不但没能在总体上降低 Minor GC 的频率,还会把 gc 的时间间隔搞得很不平均。把 Eden : Survivor 设成 1 : 1 也一样,每当对象总大小满 5 MB 的时候都必须触发一次 Minor GC ,唯一的变化是 gc 的时间间隔相对平均了。
    设置两个survivor可以保证永远有一个是空的,每次Minor GC将一个survivor和Eden区的存活对象复制到另一个survivor,再清空这个survivor和Eden,每循环一次记一次数。

什么时候进行MinorGC和FullGC
触发Minor GC
1 Eden区满了会触发Minor GC

触发FullGC
1 调用System.gc,建议执行full GC,但不一定马上执行
2 老年代空间不足
3 方法区空间不足
4 通过Minor GC进入老年代的对象内存大于老年代剩余内存
5 堆中分配很大的对象(新生代存不下的会直接进入老年代),而老年代没有足够的空间


创建对象的过程
在这里插入图片描述


堆栈的数据结构

  • 栈:具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取。
  • 堆:经过排序的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。由于堆的这个特性,常用来实现优先队列,堆的存取是随意的。

为什么要划分堆和栈

  • 栈用来代表逻辑,堆用来代表数据。这样一来逻辑就一目了然了。
  • 堆里面的数据是线程共享,栈是私有的,划分开可以节省空间,不需要创建相同的共享堆数据。

判断对象是否回收的流程
在这里插入图片描述


类加载过程
在这里插入图片描述


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值