Android内存泄漏相关

woobhurk 5年前

来自: http://blog.csdn.net/u011669081/article/details/50575430

Android开发过程中,因为开发的不规范,数据处理的不当方式,常常会造成内存泄漏。内存泄漏,可以用一句话来概括,该释放的对象未释放。

在Java方面探讨:Java语言是有垃圾回收机制的,理论上是没有泄漏的,但事实上有些情况下,Java的垃圾回收机制是无法做到垃圾回收的,例如:我们使用完一个对象后,并且不再使用,但是仍然保留着对这对象的引用,那么垃圾回收器就无法去回收这对象,造成不必要的内存泄漏。相比于C语言不同,C语言本身没有垃圾回收机制,需要程序员自己去编写操作内存。先来了解下Java GC(Garbage Collection)垃圾回收机制,简单的来说,垃圾回收机制对JVM(Java Virtual Machine)中的内存做处理,判断哪些内存需要被回收,然后根据一定策略去释放被占有的内存,保证JVM内存的足够空间。

垃圾回收机制会做三件事:

- 判断哪些内存需要回收 - 什么时候开始回收 - 怎么去回收内存

理解垃圾回收机制需要知道的几点:

- 内存是怎么分配的?

堆区:在垃圾回收机制中,堆区是垃圾垃圾回收机制中最大的管理内存的区域,堆区由所有线程共享。堆区的存在是为了存储对象实例,理论上说,所有的对象都在堆区上分配内存。

方法区(Method Area)(引用下别人的总结):在Java虚拟机规范中,将方法区作为堆的一个逻辑部分来对待,但事实 上,方法区并不是堆(Non-Heap);另外,不少人的博客中,将Java GC的分代收集机制分为3个代:青年代,老年代,永久代,这些作者将方法区定义为“永久代”,这是因为,对于之前的HotSpot Java虚拟机的实现方式中,将分代收集的思想扩展到了方法区,并将方法区设计成了永久代。不过,除HotSpot之外的多数虚拟机,并不将方法区当做永 久代,HotSpot本身,也计划取消永久代。本文中,由于笔者主要使用Oracle JDK6.0,因此仍将使用永久代一词。方法区是各个线程共享的区域,用于存储已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、编译器即时编译的代码等。方法区在物理上也不需要是连续的,可以选择固定大小或可扩展大小,并且方法区比堆还多了一个限制:可以选择是否执行垃圾收集。一般的,方法区上 执行的垃圾收集是很少的,这也是方法区被称为永久代的原因之一(HotSpot),但这也不代表着在方法区上完全没有垃圾收集,其上的垃圾收集主要是针对 常量池的内存回收和对已加载类的卸载。

程序计数器:程序计数器是个非常小的内存区域,通常只用来标记程序运行到哪行代码,字节码解释器在工作时,会通过改变这个计数器的值来取下一条语句指令。

虚拟机栈:线程内的每个方法在运行的同时,都会创建一个栈帧。栈帧中存储的有:

1. 局部变量表

2. 操作站

3. 动态链接

4. 方法出口

方法被调用时,栈帧在JVM栈中入栈,当方法执行完成时,栈帧出栈。

局部变量表中存储着方法的相关局部变量,包括数据类型,对象引用,返回地址。

虚拟机栈中定义了两中异常:

1.栈溢出:线程调用的栈深度大于虚拟机允许的栈深度。

2.内存溢出:多数JVM都允许动态扩展虚拟机栈的大小(有少部分是固定长度的),所以线程可以一直申请栈,直到内存不足。

本地方法栈:类似于虚拟机栈,唯一的区别是:虚拟机栈是执行Java方法的,而本地方法栈是用来运行native方法的。

Java内存分配机制

Java内存分配机制:分代分配,然后分代回收。

对象根据对象的存活时间被分为:年轻代,年老代,永久代。

1.年轻代:对象被创建时,内存的分配通常发生在年轻代,大多数对象在创建后很快就基本不再使用了,于是被年轻代的垃圾回收机制回收了。关于年轻代:分为三个区域,一个Eden区,两个存活区。同时年轻代方面遵守以下几条:1.绝大多数会创建在Eden区,其中大多数对象会很快消亡,Eden区是连续的内存空间,所以在分配内存上速度极快。2.当Eden区存满时,将消亡的对象清理掉,并将剩余的对象复制到一个存活区0。3当存活区0也满时,将存活的对象直接复制到存活区1。总的来说:Eden区是连续空间,而存活区总有一个保持为空。

</div>