本文将带你了解Android应用开发Android面试题:Java垃圾回收机制和finalize(),希望本文对大家学Android有所帮助。
<
Android面试题:Java垃圾回收机制和finalize()。
1. 垃圾回收的意义
在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾回收意味着程序不再需要的对象是”无用信息”,这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片。由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。
垃圾回收能自动释放内存空间,减轻编程的负担。这使Java 虚拟机具有一些优点。首先,它能使编程效率提高。在没有垃圾回收机制的时候,可能要花许多时间来解决一个难懂的存储器问题。在用Java语言编程的时候,靠垃圾回收机制可大大缩短时间。其次是它保护程序的完整性, 垃圾回收是Java语言安全性策略的一个重要部份。
垃圾回收的一个潜在的缺点是它的开销影响程序性能。Java虚拟机必须追踪运行程序中有用的对象,而且最终释放没用的对象。这一个过程需要花费处理器的时间。其次垃圾回收算法的不完备性,早先采用的某些垃圾回收算法就不能保证100%收集到所有的废弃内存。当然随着垃圾回收算法的不断改进以及软硬件运行效率的不断提升,这些问题都可以迎刃而解。
2. 垃圾收集的算法分析
Java语言规范没有明确地说明JVM使用哪种垃圾回收算法,但是任何一种垃圾回收算法一般要做2件基本的事情:
(1)发现无用信息对象;
(2)回收被无用对象占用的内存空间,使该空间可被程序再次使用。
判断这两点比较常见的方法:引用计数法与可达性分析算法。
2.1 引用计数法(Reference Counting Collector)
该方法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1,当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。
引用记数法逻辑比较简单,运行速度也比较快。但是它有一个致命的缺点,无法解决循环引用问题。
例如,A引用B,B也引用A,它们处于互相引用的状态。
?1234A a = new A(); B b = new B();a.ref = b;b.ref = a;
此时,A和B各被引用两次。
?12a = nullb = null
这时我不再想使用这两个对象,将变量引用置为null,此时,A和B的引用计数各减1。但是,它们还是各被引用了1次,所以垃圾回收器无法回收这两个对象。
2.2 可达性分析算法
在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的。这个算法的基本思路就是通过一系列名为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,下图对象object5, object6, object7虽然有互相判断,但它们到GC Roots是不可达的,所以它们将会判定为是可回收对象。
那么那些点可以作为GC Roots呢?一般来说,以下情况的对象可以作为GC Roots:
- 虚拟机栈(栈桢中的本地变量表)中的引用的对象
- 方法区中的类静态属性引用的对象
- 方法区中的常量引用的对象
- 本地方法栈中JNI(Native方法)的引用的对象
3. finalize方法
finalize是在回收一个对象之前会先调用finalize方法。但是这个调用时机是不确定的,并且在不同的jvm中调用时机也是不确定的,最后,它可能还不会被执行!所以,我们并不能依赖finalize方法做一些事情。
但是,finalize有什么用呢?
释放非java代码创建的存储空间
这种情况出现在使用“本地方法的时候(jni中)”,例如你可能调用C的malloc()函数来分配存储空间,而且除非调用了free()函数,否则无法释放该存储空间,造成内存泄漏。
在这种时候就可以在finalize方法中再次调用本地方法释放,虽然finalize调用的时机不可预料或者不被调用,但总比不释放好。
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!