主要普及下Java内存回收方法的一些常识知识。
【异常原因】
个人认为异常的原因有两种:
一:jvm分配的内存本身较小,不能满足应有的内存需求-------------内存溢出;
二:部分不能回收的对象产生堆积导致内存变小,或者出现死循环----内存泄漏。
例如:对于Java堆,我们知道了它保存Java所有实例的对象的,那么只要不断创建对象,并且创建的时间小于GC回收的时间,就会在对象数量达到堆最大容量后产生溢出异常。造成异常的原因对应上面的两种,但是我们该如何去区分问题是内存溢出还是内存泄漏呢?
思路:
通过内存映像分析工具(例如:eclipse memory analyzer)对dump出来的堆转存储快照进行分析,确认内存中的对象是否有必要,以此判断为内存泄漏还是内存溢出。如果是内存泄漏,通过工具查看泄漏对象到GC Roots的引用链,找到泄漏对象的信息,然后决定是否处理掉;如果是内存溢出,检查虚拟机中的堆参数(-Xmx和-Xms)重新调整内存大小。
【内存溢出和内出泄漏】
内存溢出:
比较简单,JVM内存设置小了或者一次性读的数据过大导致被分配的内存大小不足应付请求。
内存泄漏:
JAVA是支持垃圾回收机制的,在这样的一个背景下,内存泄露又被称为“无意识的对象保持”。如果一个对象引用被无意识地保留下来,那么垃圾回收器不仅不会处理这个对象,而且也不处理被这个对象引用的其它对象。“内存泄露”就是内存中某些内存不可被回收。
【引用计数算法和根搜索算法】
java堆存储着Java中所有的对象,如何对它进行动态的内存回收呢?Java中拥有垃圾回收机制---GC。GC通过判断对象是否“活着”?决定是否回收。是否活着的关键是看这个对象是否被“引用”。判断对象是否被引用有两个比较出色的方法。
1.引用计数算法:
给对象添加一个引用计数器,每当被引用时,则引用计数器+1,反之-1。当引用计数器为0时,则GC回收该对象。但是这个算法有个问题:无法解决两个对象互相引用的问题,即对象A引用B,对象B引用A,在这样的情况向,GC是无法回收对象A和B的。Java也因此有采用了另一个算法-----跟搜索算法。
2.根搜索算法:
通过名为“GC Roots”的对象作为起点,从起点向下搜索,搜索的路径被称为引用链,当一个对象不能到达这些起点时被称为无引用链,也就是说该对象无引用,可以被回收。
但是对于Java来说,Java将引用划分为强、软、弱、虚四种引用,对于一些可有可无的引用,只有在内存容量达到警戒值时才会释放,也就是说Java中的GC对于根搜索算法的结果不会马上释放,而是打上一次标记,当第二次搜索结果后,释放打了两次标记的对象。
学习之初,多有不足。不足之处,请多指出。