Android——内存泄漏

1. 什么是内存泄漏和内存溢出

内存泄漏:可以简单地理解为内存丢了,也就是说new之后忘记释放掉了,导致内存一直在被占用,程序无法再使用这个内存单元,直到程序结束才能使用。这就是内存泄漏了。

内存溢出:溢出就是装不下,漫了出来,比如为一个变量开辟了一个int类型的空间,却要把一个long型或float型的数据存进去,这个就是溢出。

多次或者大量的内存泄漏最终会导致内存溢出,从而导致OOM(out of memory)。

 

2. java中的内存架构

图片来源(https://my.oschina.net/xiaohui249/blog/170013)

下图是JVM的结构示意图,每当启动一个java程序时,就会相应地创建一个虚拟机实例。

(1) Garbage Collection:java的垃圾回收机制,主要就是负责回收堆中的对象(该对象不再被引用)。

(2) Classloader Sub-System:java中的类加载系统,每一个class类只会被加载器加载一次,加载主要有两种方式(懒汉:需要的时候才加载,饿汉:首先加载完成)。加载器主要用来定位和导入二进制class文件。

(3) Execution Engine:JVM中的执行引擎,主要就是负责执行包含在加载器中方法的指令。JNI以及Native Library的存在是为了弥补java的缺陷,java在运行速度上比C++慢许多,而且无法访问操作系统底层,所以native和JNI就相当与java和C之间的接口,是为了使用C的一些程序而存在的。

(4) Java Memory Allocation Area:java的虚拟机内存,也就是执行时的数据区。

 

 

java的虚拟机内存又主要分为几个部分

(1) 堆(Heap):存放new创建的对象和数组,java的gc机制也主要是对这部分来进行操作的。JVM只有一个堆供所有的线程来共享

(2) 栈(Stack):java中的栈用来存放基本的数据类型以及对象的引用。JVM为每一个新的线程分配一个栈

(3) 方法区(Method Area):方法区包含所有的class变量以及static变量。方法区又叫做静态区,跟堆有些类似,是被所有的线程共享的。

(4) 程序计数器(Program Count Register):程序计数器。每次有一个新线程被创建时,都会得到一个PC寄存器(程序计数器)

(5) 本地方法栈(Native Stack):每个线程运行时自己的本地方法栈

图片来源(https://my.oschina.net/xiaohui249/blog/170013)

 

3. 为什么会产生内存泄漏哪?

java 中的堆栈是如何工作的哪

栈:当每次有新的方法运行时,就会在栈中加一个frame,也就是一个内存单元,保存该方法调用的参数,局部变量以及返回地址,而在方法结束后,对应的frame会被从栈中移除,局部变量占用的空间也会被释放。也就是说栈会自己对内存进行清理和释放。

堆:java中new的对象都会存储在堆中,当这些对象没有再被引用时,就会等待被GC回收。如果我们创建了大量的对象,而又一直被引用,就会导致这些对象一直无法释放,从而造成内存泄漏。java中的引用又分为强,软,弱,虚四种引用。而真正造成内存泄漏的其实是强引用,因为GC不会回收一个强引用的对象。

 

4. Android中可能造成内存泄漏的情景,也就是强引用持有的情况

(1) 全局进程的static变量

(2) Activity之外的一些线程,没有清空对Activity的强引用

 

5. Android中可能导致内存泄漏的具体情况

(1) static activity:在类中定义了静态的activity变量,而在activity生命周期结束后又没有清空

(2) static views:类似于上述的情况

(3) Inner Classes:内部类虽然可以提高代码的可读性以及封装性,但是如果一个内部类持有了静态变量的引用,而且忘记了销毁的时候变为null,就会导致内存泄漏

(4) Anonymous Classes:类似与Inner Classes

(5) handler:在没有执行完handler message时,activity被销毁了。或者handler使用完后并没有释放掉对象

(6) Threads

(7) TimerTask

(8) Sensor Manager

(9) SQL:数据库查询时忘了关闭掉游标Cursor,虽然可能每次查询数据量都不是很大,但是长时间的大量操作的情况下是可能出现内存泄漏的

(10) Bitmap:程序中可能使用了太多自己创建的Bitmap,而忘记释放掉,最常见的是Gallery以及ListView这种列表

 

6. Android中具体的内存泄漏分析和定位

检测内存泄漏有一些常用的工具,比如MAT工具,AndroidStudio中自带的分析工具,以及leakCanary,这些工具的使用后期打算专门写文章介绍。

在Acitivity的生命周期中,在某些方法例如onPause(), onStop(), onDestory()方法中尽量地释放一些资源

尽量使用getApplicationContext(),而避免使用create(this)

 

posted @ 2017-09-17 16:55  东木刀纹  阅读(140)  评论(0编辑  收藏  举报