菜鸟笔记
提升您的技术认知

javagc机制详解-ag真人游戏

1 概述

在 java中,对象实例都是在堆上创建。
方法区,又叫静态成员区,所有的 1 类(class),2 静态变量(static变量),3 静态方法,4 常量,5 成员方法都存储在方法区
方法区和栈区,被所有线程共享,是不安全的

  • gc机制jvm 提供,用来清理需要清除的对象,回收堆内存
  • gc由垃圾回收器守护线程执行
  • 从内存回收一个对象之前,会调用对象的finalize()方法
  • 开发者不能强制 jvm 执行 gc,gc的触发机制由 jvm 依据堆内存的大小来决定;但是可以通过不同的引用类来辅助垃圾回收器工作(弱引用或软引用)
  • system.gc() 和 runtime.gc() 会向 jvm 发送执行 gc的请求,但是 jvm 不保证一定会执行 gc
2 总结
  • 为了分代垃圾回收,java堆内存分为3代:新生代,老年代,永久代
  • 新的对象实例会优先分配在新生代,在经历几次 minor gc后(默认15次),还存活的会被迁移至老年代(某些大对象会直接在老年代分配)
  • 永久代是否执行gc,取决于采用的 jvm
  • minor gc 发生在新生代,当 eden区没有足够空间时,会发起一次 minor gc,将 eden区中的存活对象迁移至 survivor区,major gc 发生在老年代,当 升到老年代的对象,大于老年代剩余空间时,会发生 major gc
  • 发生 major gc时,用户线程会暂停,会降低系统性能和吞吐量
  • jvm的参数-xmx和-xms用来设置java堆内存的初始大小和最大值。依据个人经验这个值的比例最好是1:1或者1:1.5。比如,你可以将-xmx和-xms都设为1gb,或者-xmx和-xms设为1.2gb和1.8gb
3 堆内存的划分

java中对象都在堆上创建。为了gc,堆内存分为三个部分,也可以说三代,分别称为新生代,老年代和永久代。其中新生代又进一步分为eden区,survivor 1区和survivor 2区(如下图)。新创建的对象会分配在eden区,在经历一次minor gc后会被移到survivor 1区,再经历一次minor gc后会被移到survivor 2区,直到升至老年代,需要注意的是,一些大对象(长字符串或数组)可能会直接存放到老年代
eden与两个survivor的内存大小比例大概是 8:1:1
永久代有一些特殊,它用来存储类的元信息。对于gc是否发生在永久代有许多不同的看法,在我看来这取决于采用的jvm。大家可以通过创建大量的字符串来观察是发生了gc还是抛出了outofmemoryerror

4 gc算法
4.1 标记清除算法

分为标记清除两个阶段
首先标记出所有需要回收的对象,在标记完成后,统一回收所有被标记的对象
该算法的缺点是:效率不高,并且会产生不连续的碎片

4.2 复制算法

把内存空间划为两个区域,每次只使用其中一个区域
垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。
算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去后还能进行相应的内存整理,不会出现"碎片"问题
优点:实现简单,运行高效。 缺点:会浪费一定的内存
一般新生代才用这种算法

4.3 标记整理算法

标记阶段与标记清除算法一样,但后续并不是直接对可回收的对象进行清理,而是
让所有存活对象都向一端移动,然后清理
优点:不会造成内存碎片

网站地图