垃圾收集器与内存分析策略

71 阅读3分钟

垃圾收集器与内存分配策略

1,概述

​ 说起垃圾收集器GC,大部分人都把这项技术当作JAVA语言的伴生产物,事实上,GC的历史比java的历史要久远。1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言。当Lisp还在胚胎的时候,人们就在思考GC需要完成的3件事情:

1)哪些内存需要回收?

2)什么时候回收?

3)如如何回收?

​ 经过半个多世纪的发展,目前内存的动态分配与内存回收技术已经相当成熟,一切看起来都进入了自动化的时代,那为什么我们还要去了解GC和内存分配呢?答案很简单:当需要排查各种内存溢出,内存溢出问题时候,当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些自动化的技术进行必要的监控和调节。

​ 把时间从半个多时间拨回到现在,回到我们熟悉的java语言,第二章java内存运行时区域各个部分,其中程序计数器,虚拟机栈和本地方法栈3个区域随线程而生,随线程而灭。栈中的栈帧随方法的进入和退出而有条不紊的进栈出栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来就已知的,因此这几个区域的内存分配和回收都具有确定性,在这几个区域就不需要考虑过多考虑回收的问题,因为方法结束或者线程结束的时候,内存自然就跟着回收了,而JAVA堆和方法堆不一样,一个接口中多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器所关注的是这部分内存,本章后续讨论中的“内存”分配与回收也仅指这一部分的内存

2,对象已经噶了吗?

​ 在堆里面存放着java世界中几乎所有的对象实例。垃圾收集器在对堆回收前,第一件事情就是确定这些对象哪些是存活的。

3,引用计数器算法

​ 很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有一个地方引用他是,计数器就加1,当引用失效的时候,计数器就减少1,任何时刻计数器为0的对象就不可能再被使用的。

​ 虚拟机并不是通过计数器算法判断对象是否存活的。

4,可达性分析算法

​ 在主流的商用语言JAVA的主流实现中,都是通过可达性分析来判断对向是否存活。这个算法的基本思路是通过一些列的叫做GC Roots 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径叫做引用链,当一个对象到GC Roots没有任何引用链相连,则证明这个对象是不可用的。