垃圾回收

背景

与C++对比,C++的内存回收是有C++的代码控制的,而JAVA的内存回收是由JVM的垃圾回收器控制的,看起来JAVA的垃圾回收更“自动化”,但是当需要排查内存溢出和内存泄漏问题时,垃圾回收器成为系统的瓶颈,此时就需要对这些“自动化”的技术实施监控和调节。

  • 内存溢出:程序报警分配的内存空间不够用
  • 内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
  • 内存泄漏会导致内存溢出

GC的区域

jvm的运行时数据区主要分为方法区、堆、虚拟机栈、本地方法栈、程序计数器。
其中,虚拟机栈、本地方法栈、程序计数器是线程私有的,一旦线程执行完成,内存就会自然回收。
方法区、堆是线程共用的,不会随着线程结束而回收,所以GC主要是针对方法区和堆。

GC的的目标对象

决定对象的内存空间是否需要被回收,主要由两种方式引用计数和可达性分析

引用计数

引用计数的方式可以简单高效的实现,但是因为存在缺陷(一旦出现循环引用则永远不能被回收),所以没有的jvm的GC中是用,

可达性分析

可达性分析是指从GC ROOTS出发,根据依赖关系是否可以达到指定的对象,如果可达,则对象不能被回收,如果不可能,则对象可以被回收。
另外,除了强引用外,还有软引用、弱引用、虚引用等,主要一次随着应用强度而减弱,而在空间回收时,按照相反次序进行内存回收。

GC roots的对象主要扩一下四种:

  • 虚拟机栈引用的对象
  • 本地方法栈应用的对象
  • 方法区引用的对象
  • 常量池引用的对象

GC的算法

垃圾回收的算法主要包括四种:

  • 标记-清除
  • 标记-复制
  • 标记-整理
  • 分带收集算法

标记-清除

一次标记,一次请求,缺点是回收效率低,并且造成大量的内存碎片,虽然有诸多缺点但是却是其他后续的算法的基础

标记-复制

将空间分成相等的两部分,每次只使用一块,虽然效率提高,但是也造成了大量的空间浪费

标记-整理

在“标记-清除”的基础上,对剩余的空间进行碎片整理,这样提高了空间的使用率,降低了下次分配内存空间因为连续空间不足而导致需要再次GC的问题

分带收集算法

根据对象的生命周期特性,90%以上新生对象是很快就要被回收的,所以整体上将内存空间分为新生代和老年代,并且将新生代分为Eden和两个相等的Survivor区。新生对象分配的空间在Eden和一个survivor中,每次minor GC后,将存货的对象负责到另一个survivor上。
默认参数-XX:SurvivorRatio=8
Eden:s0:s1=8:1:1

GC的类型

  • serial
  • ParNew
  • CMS
  • Parallel
  • parallel Old
  • serial old
  • G1

GC的日志

  • 进程实例运行时间
  • GC类型
  • GC区域
  • 区域的内存空间变化
  • 实例的内存空间变化
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容