80.Android之内存管理
转载:http://www.jianshu.com/p/9fb0a795da93
1. Android中的内存
1.1 Android中的垃圾回收机制
Android 平台最吸引开发者的一个特性:有垃圾回收机制,无需手动管理内存,Android 系统会自动跟踪所有的对象,并释放那些不再被使用的对象
Young Generation 新生代
- 大多数新建对象都位于Eden(伊甸园)区
- 当Eden区被对象填满时,就会执行Minor GC(轻量GC)。并把所有存活下来的对象转移到其中一个survivor区
- Survivor Space:S0、S1有两个,存放每次垃圾回收后存活的对象
Minor GC 同样会检查survivor区中存活下来的对象,并把他们转移到另一个survivor区,这样在一段时间内,总会有一个空的survivor区
Old Generation 老生代
- 存放长期存活的对象和经过多次Minor GC后依然存活下来的对象
满了进行Major GC(较重GC)
Permanent Generation 永久代
存放方法区,方法区中有,要加载的类信息、静态变量、final类型的常量、属性和方法信息
1.2 垃圾回收
- 内存占用过多,需要为新对象分配空间
- 不同的虚拟机发生GC时采用的策略不同,可能会暂停当前程序的执行
1.3 垃圾回收机制&FPS
- Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,那么整个过程如果保证在16ms以内就能达到一个流畅的画面。60FPS
- 如果某一帧的操作超过了16ms就会让用户感觉到卡顿
- UI渲染过程发生GC,导致某一帧绘制时间超过16ms
1.4 内存泄漏
在整个Android开发过程中,内存泄漏是导致OOM(Out Of Memory内存溢出)的一个重要因素
- 应用程序分配了大量不能回收的对象
- 这导致可分配的内存越来越少
- 当新对象的创建需要的内存不够
- 当发现内存不够就会调用一次GC进行垃圾回收
- 结果:就会发生卡顿
1.5 内存抖动
原因:内存抖动是因为应用程序在短时间内创建大量的对象,又被马上释放。
- 瞬间产生大量的对象会严重占用Young Generation的内存区域
- 当达到阈值,剩余空间不够,就会触发GC从而导致刚产生的对象又很快被回收。
- 即时每次分配的对象占用了很少的内存,频分GC叠加在一起会增加Heap的压力
- 从而触发更多其他类型的GC。
- 结果:这个操作有可能会影响到帧率,并使用户感知到性能问题
2. 内存检测工具
2.1 Memory Monitor 内存监视器
- 优点
- 方便显示内存使用和GC情况
- 快速定位卡顿是否和GC有关
- 快速定位Crash崩溃是否和内存占用过高有关
- 快速定位潜在的内存泄漏问题
- 简单易用
- 缺点
- 不能准确定位问题
2.2 Allocation Tracker 分配跟踪器
- 优点
- 定位代码中分配对象的类型,大小,时间,线程,堆栈等信息
- 定位内存抖动问题
- 配合HeapViewer一起定位内存泄漏问题
- 缺点
- 使用复杂
- 显示所有对象的信息(环形图)
2.3 Heap Viewer 堆视图
- 优点
- 内存快照信息
- 每次GC之后收集一次信息
- 查找内存泄漏利器
- 缺点
- 使用复杂
- 显示已分配的对象大小信息(包视图)
2.4 Leak Canary
引用
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
}使用
// 内存泄漏检测
private RefWatcher refWatcher;
public static RefWatcher getRefWatcher(Context context) {
TTApplication application = (TTApplication) context.getApplicationContext();
return application.refWatcher;
}
@Override
public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this); // 检测
} public void onDestroy() {
RefWatcher refWatcher = TTApplication.getRefWatcher(getActivity());
refWatcher.watch(this); //内存泄露检测
}</code>
3. 常见的内存泄漏问题
3.1 单例造成的泄漏
将Context对象保存在单例模式中,instance对象本身持有一个Context对象的引用,活动即时被销毁也不能被回收,因为静态变量一直持有它的引用
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static AppManager getInstance(Context context) {
if (instance != null) {
instance = new AppManager(context);
}
return instance;
}
}
可以改为
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
// 使用Application的Context(也可以用自定义的Application)
this.context = context.getApplicationContext();
}
public static AppManager getInstance(Context context) {
if (instance != null) {
instance = new AppManager(context);
}
return instance;
}
}
3.2 非静态内部类的静态实例造成的泄漏
静态的sResource在创建时会间接持有一个MainActivity实例的引用,导致MainActivity无法被回收
public class MainActivity extends Activity {
private static TestResource sResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (sResource == null) {
sResource = new TestResource();
}
// ...
}
// 非静态内部类
class TestResource {
// ...
}
}
将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例
如果用到Context就使用Application的Context
但是Dialog不能使用Application和Service的Context
3.3 Handler 造成的内存泄漏问题
当创建匿名对象时,该对象会间接持有外部类实例的一个引用,mHandler对象本身会持有MainActivity的引用,导致MainActivity销毁后无法即时被回收
public class MainActivity extends Activity {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
}
private void loadData() {
// ...request
Message message = Message.obtain();
mHandler.sendMessage(message);
}
}
在Activity中避免使用非静态内部类,比如将Handler声明为静态的,这样Handler的存活时间就与Activity无关了
同时引入弱引用的方式引入Activity,避免将Activity作为Context传入
使用前判空
public class MainActivity extends Activity {
private static class MyHandler extends Handler {
private final WeakReference<MainActivity> mActivity;
private MyHandler(MainActivity activity){
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
}
private void loadData() {
// ...request
Message message = Message.obtain();
mHandler.sendMessage(message);
}
}
3.4 集合类泄漏
- 如果集合类是全局的变量(类中的静态属性,全局性的map等既有静态引用或final一直指向它)
- 没有相应的删除机制
- 很可能导致集合所占用的内存只增不减
4. 避免内存泄漏的方法
- 尽量不要让静态变量引用Activity
- 使用WeakReference弱引用,会保证GC时会被回收
- 使用静态内部类来代替内部类,静态内部类不持有外部类的引用
- 静态内部类使用弱引用来引用外部类
- 在声明周期结束的时候释放资源
5. 减少内存使用
使用更轻量的数据结构(SpareArray代替HashMap)
- Google自己定义的类占用内存更小
避免在onDraw方法中创建对象
- onDraw()方法被频繁调用,在其中创建对象会导致临时对象过多,发生内存抖动
对象池(Message.obtain())
- 当一定要在onDraw中创建对象,推荐使用对象池
- 相当于对象缓冲,在创建时查找是否已经存在对象,没有在创建
LRUCache
- 大大减少内存使用
Bitmap内存复用,压缩(inSampleSize,inBitmap)
StringBuilder
- 代替String,尤其是进行拼接操作时
80.Android之内存管理的更多相关文章
- Android 之 内存管理-查看内存泄露(三)
概述 在android的开发中,要时刻主要内存的分配和垃圾回收,因为系统为每一个dalvik虚拟机分配的内存是有限的,在google的G1中,分配的最大堆大小只有16M,后来的机器一般都为24M,实在 ...
- 自己写的书《深入理解Android虚拟机内存管理》,不出版只是写着玩
百度网盘地址:https://pan.baidu.com/s/1jI4xZgE 我给起的书名叫做<深入理解Android虚拟机内存管理>.本书分为两个部分,前半部分主要是我对Linux0. ...
- 正确认识Android的内存管理机制,合理关闭进程 (一)
随着大家收货后会有很多乐粉晒内存,为啦方便大家,在网上搜集了一些相关Andriod管理的相关机制合理管理内存,整理下发个贴. 首先要知道Android系统是基于Linux 2.6内核开发的开源操作系统 ...
- 学习android内核 -- 内存管理相关
Android内存管理: 1.当应用程序关闭以后,后台对应的进程并没有真正的退出(处于休眠状态,一般不占用系统CPU的资源),这是为了下次再启动的时候能快速启动. 2.当系统内存不够时,AmS会主动根 ...
- 安卓Android的内存管理原理解析
Android采取了一种有别于Linux的进程管理策略,有别于Linux的在进程活动停止后就结束该进程,Android把这些进程都保留在内存中,直到系统需要更多内存为止.这些保留在内存中的进程通常情况 ...
- Android app内存管理的16点建议
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiopshared memory(共享内存) Android通过下面几个方式在不同的Process中来共享RAM: 每一个app的proc ...
- C程序内存管理
C程序的内存管理 熟悉Java语言的肯定知道,Java中内存管理是由虚拟机帮助我们完毕的,在C/C++中可不是这样,程序猿须要自己去分配和回收内存空间.本文记录了C程序可运行文件的存储结构.在内存中的 ...
- Android Dalvikvm 内存管理理解
网上非常多文件介绍了 jvm 内存管理的理论,但在 Dalvikvm 中,到底是怎样实现的. 这几天猛看了 Dalvikvm 的源码,说一下我的理解: 在大层面上讲跟理论一样,jvm 把内存分成了一些 ...
- android 图片内存管理
图片对象: drawable bitmap etc.图片对象在Android上该缓存吗?什么时候缓存?怎么缓存?缓存后使用时怎么取出?怎么销毁?什么时候销毁? bitmap对象(new出来的) :需要 ...
随机推荐
- HTML 学习笔记 CSS样式(框模型)
CSS框模型( Box Model)规定了元素框处理元素的内容 内边距 边框 和 外边距的方式 CSS框模型概述 可以用下面的模型图概述
- Location 对象
Location 对象 Location 对象包含有关当前 URL 的信息. Location 对象是 window 对象的一部分,可通过 window.Location 属性对其进行访问. 注意: ...
- PAT 1015. 德才论 (25)
宋代史学家司马光在<资治通鉴>中有一段著名的"德才论":"是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人.凡取人之术,苟不得圣人,君子 ...
- Webwork 学习之路【01】Webwork与 Struct 的前世今生
Struts 1是全世界第一个发布的MVC框架,它由Craig McClanahan在2001年发布,该框架一经推出,就得到了世界上Java Web开发者的拥护,经过长达6年时间的锤炼,Struts ...
- Scala之OOP
/** * 1,在Scala中定义类是用class关键字: * 2,可以使用new ClassName的方式构建出类的对象: * 3, 如果名称相同,则object中的内容都是class的静态内容,也 ...
- 【JavaEE企业应用实战学习记录】struts2实现登录并获取各个范围的数据
package sanglp; import com.opensymphony.xwork2.*; /** * Created by Administrator on 2016/10/6. */ pu ...
- Beta--项目冲刺第六天
胜利在望-- 队伍:F4 成员:031302301 毕容甲 031302302 蔡逸轩 031302430 肖阳 031302418 黄彦宁 会议内容: 1.站立式会议照片: 2.项目燃尽图 3.冲刺 ...
- CAP理论
自打引入CAP理论的十几年里,设计师和研究者已经以它为理论基础探索了各式各样新颖的分布式系统,甚至到了滥用的程度.NoSQL运动也将CAP理论当作对抗传统关系型数据库的依据. CAP理论主张任何基于网 ...
- C++折半插入排序
代码如下: #include <iostream> using namespace std; void insertSort(int a[], int n) { for(int i=1;i ...
- html5 播放多个视频。一个接一个的播放
new个video,指定播放列表的第一个视频路径为src.监听end事件,回调里面把video的src改成列表的下一个,再play. 示意代码:var vList = ['视频地址url1', 'ur ...