gc

简介

概述

java与c很大的区别就是gc(自动垃圾回收机制)

gc是在方法区和堆中进行工作的,栈中和程序计数器中没有gc

当虚拟机发现堆中的内存不够用了,会触发gc

gc判断对象存存货的方式主要有俩种,引用计数法(python),和可达性分析

java中使用的是可达性分析

jvm内存区域

jvm与你及运行时数据区分为

程序计数器

存放虚拟机字节码指令的地址,程序计数器是线程私有的,每一个线程都有独立的线程计数器且互不干扰,并且程序计数器永远不会发生内存泄漏

存放对象实例和数组,它是运行时数据最大的一篇区域

虚拟机栈

存放java方法,基本数据类型和引用数据类型,操作数栈,动态链接和方法出口。虚拟机栈是线程私有的而且生命周期与线程相同。特点是先进后出

本地方法栈

存放的是本地方法,一些底层的方法,可能是用c和c++编写的

方法区

存放类信息,常量,静态变量,即使编译器后的代码

内存分配与回收策略

判断对象已死算法

引用计数器算法

简单概括为:给一个对象添加一个引用计数器,每当有一个地方引用该对象的时候,计数器+1,当引用失效的时候,计数器-1,任何时刻,计数器为0的时候,该对象不在被引用

引用计数器实现很简单,判定效率也很高,大部分场景是一个不错的选择。但是当前主流的jvm没有采用标记清除算法,原因在于,它很难1解决对象之间胡夏你给循环调用的情况

可达性分析算法

在主流的商用语言(如c#,java)的主流实现中,都是可以通过可达性分析来判断对象是否存货,这个算法的思想就是通过1一些列的成为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径成为引用链,当一个对象到GC Roots没有任何引用链相连,则证明此对象是不可用的。

在java中可以作为gc Roots对象的包括以下几种

  • 虚拟机栈中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(native方法)的引用的对象

引用

无论通过引用计数器还是可达性分析,判断出的引用链是否可达,判断对象是否存活都跟引用有关

jdk1.2之后堆引用进行重新的扩充

强引用

强引用时在代码中普遍存在的,只要new一个对象赋值给变量,就是强引用,只要强引用一直存在,垃圾收集器永远不会回收被引用的对象

软引用

软引用用来描述一些还要用但是并非必须的对象,对于软引用关联着的对象,当内存溢出发生之前,通过垃圾回收进行二次回收,如果二次回收完成后,系统内存依然不够才会抛出内存溢出异常

弱引用

若引用也是用来描述非必须对象的1,但他的强度相对于软引用更弱一些,它仅仅能生存道下一次的垃圾回收之前。当垃圾收集时,无论内存是否足够若引用的对象都要被回收

虚引用

虚引用是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会堆其生存时间构成影响,也无法通过一个虚引用获取一个实例对象。为对象设置一个虚引用唯一的它能够跟踪垃圾回收过程.

垃圾回收算法

标记清除

这是最基础的回收算法,它最容易实现,标记清除分为俩个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间

但这种算法有一个比较严重的问题就是容易产生内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前出发新的一次垃圾收集工作

复制算法

它可以将可用内存按容量划分为大小相等的俩块,每次只使用其中的一块,当这一块用完了,九江还存活着的对象复制到另一块上面,任何再把已使用的内存空间一次清理掉,这样一来就不容易出现内尺寸碎片的问题

这种算法虽然简单,巡行搞笑且不容易产生内存碎片,但是却堆空内存的使用做了高昂的代价,因为能够使用的内存缩减到原来的一半,很显然复制算法的效率跟存活对象的数目多少有很大的关系,如果存活对象很多,那么复制算法的效率将会大大降低

分代收集算法

分带手机算法是目前大部分jvm的垃圾回收期采用的算法,它的核心思想是根据对象存货的生命周期将内存划分为若干个不同的区域。老年代和年轻带,年轻带里头又分为eden区和survivor区,survivor又分为from和to区。通常默认的比例为8:1:1,每次只保留10%的空间用作预留区域,任何将百分之90%的空间可以用作新生对象,每一次进行垃圾回收之后,存活的对象年龄+1,当经历15此还依然存活的对象,我们直接让它进入老年代

另一种进入到老年代的方式是内存担保机制,也就是当新生代空间不够的时候,对象直接进入到老年代

Last modification:May 12, 2020
如果觉得我的文章对你有用,请随意赞赏