一、JVM内存模型与分布
我们都知道JVM运行时的数据区域分为5大块
image.png- 1.程序计数器:虚拟机字节码的行号记录器,占用内存非常小,可以不用考虑。
- 2.虚拟机栈:这个区域描述的是java方法执行的内存模型,每个方法代表一个栈帧,方法内大部分定义的变量都是栈里面的成员,他是有生命周期的,伴随着方法执行结束而销毁。
- 3.本地方法栈:同虚拟机栈很相似,但他是Native层的。
- 4.堆:几乎所有对象都在这个区域产生,该区域属于线程共享区域,所以线程销毁时,需要注意对象的销毁
- 5.方法区::主要存储虚拟机加载的类信息,常量,静态变量,及时编译器编译后的代码等数据。
二、内存限制
android是基于Linux系统的,android中的进程分为两种:
- 1.native进程:采用C/C++实现,不包含dalvik实例的linux进程,/system/bin/目录下面的程序文件运行后都是以native进程形式存在的
-
2.java进程:实例化了dalvik虚拟机实例的linux进程,进程的入口main函数为java函数。dalvik虚拟机实例的宿主进程是fork()系统调用创建的linux进程,所以每一个android上的java进程实际上就是一个linux进程,只是进程中多了一个dalvik虚拟机实例
我们知道,操作系统对进程的内存是有限制的,而且操作系统对dalvik虚拟机自身的堆内存大小也是有限制的。可以通过如下命令查看限制大小:
adb shell getprop | grep dalvik.vm.heapgrowthlimit
可以在Androidmanifest文件中application节点加入android:largeHeap=“true”来增加其dalvik虚拟机中堆的大小
我们常说的堆大小其实是包涵两部分的,一是java的堆,而是native的堆,java堆中主要是一下java对象,由 C/C++申请的内存空间则在native堆中,也有一些对象需要结合native和java堆共同完成,比如bitmap,bitmap分为bitmap对象和其中存储的像素值,对象分配在java堆,而存储的像素值则根据版本不同存储的位置也不同,api 11 - api 25是存储在java堆中的,其他版本是存储在native堆中的
三、内存泄漏场景
1.静态引用
静态对象非法持有Activity上下文
2.匿名内部类,或非静态内部类
Handler,AsyncTask,TimerTask等,一般在处理多线程任务的时候
3.监听器
在Activity OnResume里面registListener,在OnPause一定要记得unregistListener
4.资源对象
BraodcastReceiver, ContentObserver,File,Cursor,Stream,Bitmap,Socket等资源,使用后未关闭会导致内存泄漏。这些对象JVM中有的只保存引用,而真实的数据存在JVM之外的内存,所以并非对象制为null即可,必须 调用 recycle, release, close等方法,清空内存。
4.WebView
在Activity的onDestory中调用 WebView的 clearHistory, clearView,destroy方法即可。
四、如何排查以及修复
1.LeakCanary
2.Android Studio 3.0 的 Android Profiler 分析器
五、如何进一步进行优化
- 1.资源优化:
1.shape代替图片资源
2.部分png图改jpg图,比如启动页
3.gradle配置shrinkResources属性,删除无效资源
- 2.代码优化
1.删除冗余代码,减少编译带来的内存开销
2.第三方库so包的缩小, 能满足需求的情况下,尽量实用阉割版
网友评论