在我们的日应用常开发中经常会遇到性能优化的问题,如何去优化自己现有的项目,运行更加流畅,便成了我们要思考的问题。
一、内存泄漏
当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而就导致对象不能被回收。这种导致了本该被回收的对象不能被回收而停留在堆内存中,就产生了内存泄漏。
对于Android应用来说,就是你的用户打开一个Activity,使用完之后关闭它,内存泄露;又打开,又关闭,又泄露;几次之后,程序占用内存超过系统限制,FC。
二、了解GC以及内存分配的策略
GC内存回收机制:某对象不再有任何的引用的时候才会进行回收。
分配的几种策略:
1.静态的
静态的存储区:内存在程序编译的时候就已经分配好,这块的内存在程序整个运行期间都一直存在。它主要存放静态数据、全局的static数据和一些常量。
2.栈式的
在执行函数(方法)时,函数一些内部变量的存储都可以放在栈上面创建,函数执行结束的时候这些存储单元就会自动被释放掉。栈内存包括分配的运算速度很快,因为内置在处理器的里面的。当然容量有限。
3.堆式的
也叫做动态内存分配。有时候可以用malloc或者new来申请分配一个内存。在C/C++可能需要自己负责释放(java里面直接依赖GC机制)。
区别:堆是不连续的内存区域,堆空间比较灵活也特别大。栈式一块连续的内存区域,大小是有操作系统觉决定的。堆管理很麻烦,频繁地new/remove会造成大量的内存碎片,这样就会慢慢导致效率低下。对于栈的话,他先进后出,进出完全不会产生碎片,运行效率高且稳定。
主要讨论堆内存,他存放的就是引用指向的对象实体。
三、实例
在日常开发中我们经常使用到工具类,然而我们无心的传参却会导致我们的,内存泄漏.
例如`public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CommonUtil commUtil = CommonUtil.getInstance(this);
//我们把activitity传入我们所写的单利工具类中
}`
public class CommonUtil {
private static CommonUtil instance;
private Context context;
private CommonUtil(Context context) {
this.context = context;
}
public static CommonUtil getInstance(Context context) {
if (instance == null) {
synchronized (CommonUtil.class) {
if (instance == null) {
instance = new CommonUtil(context);
}
}
}
return instance;
}
}
在MainActivity第一次创建的时候我们的CommonUtil 持有了这个activity,将手机屏幕进行多次旋转,并进行gc释放后,发现内存中依旧有2个MainActivity,导致内存泄漏,所以我们在日常开发中要注意
CommonUtil commUtil =CommonUtil.getInstance(this);
更改为
CommonUtil commUtil = CommonUtil.getInstance(getApplicationContext());
//解决生命周期一致而不产生内存泄漏的问题
四、handler导致内存泄漏
概述:
handler的不规范使用也会产生内存泄漏的问题,相关的文章也很多。
造成的常见情况是:当使用内部类(包括匿名类)来创建Handler的时候,,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用,当后台耗时线程未执行完时,关闭activity,导致activity无法回收,导致内存泄漏
主要是2种解决方案
方法一:通过程序逻辑来进行保护。
1.在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
2.如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。
方法二:将Handler声明为静态类。
静态类不持有外部类的对象,所以你的Activity可以随意被回收
static class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
mImageView.setImageBitmap(mBitmap);
}
}
使用了以上代码之后,你会发现,由于Handler不再持有外部类对象的引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你需要在Handler中增加一个对Activity的弱引用(WeakReference)
static class MyHandler extends Handler {
WeakReference<Activity > mActivityReference;
MyHandler(Activity activity) {
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
mImageView.setImageBitmap(mBitmap);
}
}
}
五、扩展
StrongReference强引用:
回收时机:从不回收 使用:对象的一般保存 生命周期:JVM停止的时候才会终止
SoftReference,软引用
回收时机:当内存不足的时候;使用:SoftReference结合ReferenceQueue构造有效期短;生命周期:内存不足时终止
WeakReference,弱引用
回收时机:在垃圾回收的时候;使用:同软引用; 生命周期:GC后终止
群号:454430053,欢迎入群