您的位置:首页 > 编程语言 > Java开发

Java基础知识---垃圾回收机制简述

2017-09-26 19:38 423 查看

Java基础知识---垃圾回收机制简述

前言:

在程序不断的运行中,不可避免的就会产生许许多多不在被使用到的对象和数据,这就是我们通常说的"垃圾",太多的垃圾数据会占用内存空间导致我们程序出现各种各样的问题,所以我们需要对这些垃圾进行处理,c、c++程序员可能需要实时的对垃圾进行清理,而java则不需要去关心内存动态分配和垃圾回收的问题,这一切都归功于本次我们讲的垃圾回收机制。

本文中主要讲这四个问:
1、什么样才的对象才能被确定为垃圾?
2、确定为垃圾需要进行怎样的处理?
3、垃圾回收有哪些常见算法?
4、有哪些常见垃圾收集器?

一、什么样的对象才能被确定为垃圾

不再被使用的对象就是垃圾,那么怎么样才算是不再被使用到的对象呢?

a)引用计数算法

在java中是通过引用来和对象进行关联的,也就是说如果要操作对象,必须通过引用来进行。那么很显然一个简单的办法就是通过引用计数来判断一个对象是否可以被回收。不失一般性,如果一个对象没有任何引用与之关联,则说明该对象基本不太可能在其他地方被使用到,那么这个对象就成为可被回收的对象了。这样的算法存在很明显的问题:假如A调用B,B调用A形成了一个调用的循环,这样就的循环调用引用计数算法是无法解决的。

b)可达性分析算法

目前主流的商用于洋的主流实现中,就是采用的可达性分析算法,这个算法的基本思路就是通过一系列称为“GC
Roots”的对象作为起始点开始向下根据引用搜索,形成一个引用链,如果假如有这样一个对象不再任何引用类中,那么就可以确定这个对象时一个不被引用的“垃圾”,那么对这些不可达的对象进行标记,之后在进行回收。
PS:可以作为GC
Roots的对象包括下面几种
1、虚拟机栈(栈帧中的本地变量表)中引用的对象(方法运行时,方法中引用的对象);
2、方法区中类静态属性引用的对象(方法运行时,方法中引用的对象);
3、方法区中常量引用的对象(类中常量引用的对象);
4、本地方法栈中JNI(即一般说的Native方法)引用的对象(Native方法中引用的对象);

二、确定为垃圾需要进行怎样的处理?

被确定为“垃圾”的对象自然就会被回收,但是这被标记的对象也不是"非死不可"的,一个被判断为“垃圾”的对象至少要经过两次的标记过程,当一个对象被进行回收的时候首先会判断是否有必要执行finalize():是否重写finalized方法?是否已经执行过finalize方法?
如果满足以上任何条件那么在此标记,直接被回收。如果不满足那么久会被放入F-Queue的队列中,稍后有一个低优先级的线程对他进行处理,结束之后再进行小规模的标记,之后再回收。所以一个“垃圾”拯救自己的方法就是在finalize()中重返引用链如把this关键字赋给某个对象,但是需要明确fina-lize只会被调用一次,再次调用不会有效果,且不建议调用这个方法,因为这个方法运行代价高昂,不确定性大。finalize能做的try-catch都能做,甚至做的更好。

三、垃圾回收有哪些常见算法?

既然知道了什么是垃圾,采取什么呀的处理措施,那么久必须接着讲如何清理了,一下是几种常见的垃圾回收算法
a)标记-清除算法
这是最基础的收集算法,之后介绍的算法都是这个算法的改进。顾名思义就是将收集分为两个步骤,第一步标记,第二步收集,先标记处所以需要被回收的对象,之后再清除被标记的对象。这个算法有两个问题:1、效率不高 2、会产生不连续的内存碎片。
执行效果如图3-1
b)复制算法
这是为了解决标记清除算法的效率问题而出现的算法,他将内存分为两块每次只使用其中的一块,当一块用完了就把存活的对象放到另一块中,在清除整块区域。这样只需要移动对顶的指针,按顺序分配内存就可以了,实现简单,运行高效,但是每次需要浪一半的内存空间。
c)标记-整理算法
复制算法在对象比较多的时候就要进行较多的复制操作,效率会有所降低,关键也不想浪50%的空间,那么久提出了这样一种算法:与标记-清除一样,先对“垃圾”对象进行标记
但是后续步骤不是直接清理而是让所有活的对象都移动到一端,之后直接清理掉边界之外的内存。
d)分代算法
目前的商业虚拟机采用的都是“分代算法”,这种算法没有什么心的思路,就是根据对象的存活周期的不同将内存划分为几块,一般把堆分为新生代和老年代

 
       
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: