内存泄露如何解决?
2016-05-28 11:55
344 查看
1
、
数据库的
cursor
没有关闭
2
、
构造
adapter
没有使用缓存
contentview
衍生的
listview
优化问题:减少创建
View
的对象,充分使用
contentview
,可
以使用静态类来处理优化
getView
的过程
3
、
Bitmap
对象不使用时采用
recycle()
释放内存
4
、
Activity
中的对象生命周期大于
Activity
调式方法:
DDMS->HEAPSIZE->adtaobject->total size
Android
应用程序被限制在
16MB
的堆上运行,至少在
T-Mobile
G1
上是这样。对于
手机来说,这是很大的内存了;但对于一些开发人员来说,这算是较小的了。即使
你不打算使用掉所有的内存,但是,你也应该尽可能少地使用内存,来确保其它应
用程序得以运行。
Android
在内存中保留更多的应用程序,对于用户来说,程序间
切换就能更快。作为我(英文作者)工作的一部分,我调查了
Android
应用程序的
内存泄露问题,并发现这些内存泄露大多数都是由于相同的错误导致的,即:对
Context
拥有较长时间的引用。
在
Android
上,
Context
常用于许多操作,更多的时候是加载和访问资源。这就是
为什么所有的
Widget
在它们的构造函数里接受一个
Context
的参数。
在一个正常的
Android
应用程序里,你会看到两种
Context
类型,
Activity
和
Application
。而
一般在需要一个
Context
的类和方法里,往往传入的是第一种:
Java
代码
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
}
这意味着,
View
拥有对整个
Activity
的引用以及
Activity
自身拥有的所有内容;
一般是整个的
View
层次和它的所有资源。因此,如果你“泄露”了
Context
(“泄
露”指你保留了一个引用,阻止了
GC
的垃圾回收),你将泄露很多的内存。如果你
不够仔细的话,很容易就能泄露一个
Activity
。
当屏幕的方向发生改变时,
一般系统会销毁当前的
Activity
并创建一个新的,
并保
存它的状态。当系统这样做时,
Android
会从资源中重新加载应用程序的
UI
。假设
你写的应用程序拥有大的位图,而你又不想在每次旋转时重新加载它。这里有最简
单的方式,那就是在一个静态的字段里进行保存:
Java
代码
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
这段代码效率很快,但同时又是极其错误的;在第一次屏幕方向切换时它泄露了一
开始创建的
Activity
。
当一个
Drawable
附加到一个
View
上时,
View
会将其作为一
个
callback
设定到
Drawable
上。上述的代码片段,意味着
Drawable
拥有一个
TextView
的引用,而
TextView
又拥有
Activity
(
Context
类型)的引用,换句话
说,
Drawable
拥有了更多的对象引用(依赖于你的代码)。
这是最容易泄露
Context
的例子之一,你可以看看
Home Screen
源代码里是如何处
理的(搜索
unbindDrawables()
方法):当
Activity
销毁时,设定存储的
Drawable
的
callback
为
null
。有趣的是,还有很多一连串的
Context
泄露情况,并且是非
常糟糕的。这些情况会使得应用程序很快耗尽内存。
这里,有两种简单的方式可以避免与
Context
相关的内存泄露。最显而易见的一种
方式是避免将
Context
超出它自己的范围。上面的例子代码给出的静态引用,还有
内部类和它们对外部类的隐式引用也是很危险的。第二种解决方案是使用
Application
这种
Context
类型。
这种
Context
拥有和应用程序一样长的生命周期,
并且不依赖
Activity
的生命周期。
如果你打算保存一个长时间的对象,
并且其需要
一个
Context
,记得使用
Application
对象。你可以通过调用
Context.getApplicationContext()
或
Activity.getApplication()
轻松得到
Application
对象。
概括一下,避免
Context
相关的内存泄露,记住以下事情:
不要保留对
Context-Activity
长时间的引用
(对
Activity
的引用的时候,
必须
确保拥有和
Activity
一样的生命周期)
尝试使用
Context-Application
来替代
Context-Activity
如果你不想控制内部类的生命周期,
应避免在
Activity
中使用非静态的内部类,
而应该使用静态的内部类,
并在其中创建一个对
Activity
的弱引用。
这种情况的解
决办法是使用一个静态的内部类,其中拥有对外部类的
WeakReference
,如同
ViewRoot
和它的
Winner
类那样
GC
(垃圾回收)不能解决内存泄露问题
、
数据库的
cursor
没有关闭
2
、
构造
adapter
没有使用缓存
contentview
衍生的
listview
优化问题:减少创建
View
的对象,充分使用
contentview
,可
以使用静态类来处理优化
getView
的过程
3
、
Bitmap
对象不使用时采用
recycle()
释放内存
4
、
Activity
中的对象生命周期大于
Activity
调式方法:
DDMS->HEAPSIZE->adtaobject->total size
Android
应用程序被限制在
16MB
的堆上运行,至少在
T-Mobile
G1
上是这样。对于
手机来说,这是很大的内存了;但对于一些开发人员来说,这算是较小的了。即使
你不打算使用掉所有的内存,但是,你也应该尽可能少地使用内存,来确保其它应
用程序得以运行。
Android
在内存中保留更多的应用程序,对于用户来说,程序间
切换就能更快。作为我(英文作者)工作的一部分,我调查了
Android
应用程序的
内存泄露问题,并发现这些内存泄露大多数都是由于相同的错误导致的,即:对
Context
拥有较长时间的引用。
在
Android
上,
Context
常用于许多操作,更多的时候是加载和访问资源。这就是
为什么所有的
Widget
在它们的构造函数里接受一个
Context
的参数。
在一个正常的
Android
应用程序里,你会看到两种
Context
类型,
Activity
和
Application
。而
一般在需要一个
Context
的类和方法里,往往传入的是第一种:
Java
代码
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
}
这意味着,
View
拥有对整个
Activity
的引用以及
Activity
自身拥有的所有内容;
一般是整个的
View
层次和它的所有资源。因此,如果你“泄露”了
Context
(“泄
露”指你保留了一个引用,阻止了
GC
的垃圾回收),你将泄露很多的内存。如果你
不够仔细的话,很容易就能泄露一个
Activity
。
当屏幕的方向发生改变时,
一般系统会销毁当前的
Activity
并创建一个新的,
并保
存它的状态。当系统这样做时,
Android
会从资源中重新加载应用程序的
UI
。假设
你写的应用程序拥有大的位图,而你又不想在每次旋转时重新加载它。这里有最简
单的方式,那就是在一个静态的字段里进行保存:
Java
代码
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
这段代码效率很快,但同时又是极其错误的;在第一次屏幕方向切换时它泄露了一
开始创建的
Activity
。
当一个
Drawable
附加到一个
View
上时,
View
会将其作为一
个
callback
设定到
Drawable
上。上述的代码片段,意味着
Drawable
拥有一个
TextView
的引用,而
TextView
又拥有
Activity
(
Context
类型)的引用,换句话
说,
Drawable
拥有了更多的对象引用(依赖于你的代码)。
这是最容易泄露
Context
的例子之一,你可以看看
Home Screen
源代码里是如何处
理的(搜索
unbindDrawables()
方法):当
Activity
销毁时,设定存储的
Drawable
的
callback
为
null
。有趣的是,还有很多一连串的
Context
泄露情况,并且是非
常糟糕的。这些情况会使得应用程序很快耗尽内存。
这里,有两种简单的方式可以避免与
Context
相关的内存泄露。最显而易见的一种
方式是避免将
Context
超出它自己的范围。上面的例子代码给出的静态引用,还有
内部类和它们对外部类的隐式引用也是很危险的。第二种解决方案是使用
Application
这种
Context
类型。
这种
Context
拥有和应用程序一样长的生命周期,
并且不依赖
Activity
的生命周期。
如果你打算保存一个长时间的对象,
并且其需要
一个
Context
,记得使用
Application
对象。你可以通过调用
Context.getApplicationContext()
或
Activity.getApplication()
轻松得到
Application
对象。
概括一下,避免
Context
相关的内存泄露,记住以下事情:
不要保留对
Context-Activity
长时间的引用
(对
Activity
的引用的时候,
必须
确保拥有和
Activity
一样的生命周期)
尝试使用
Context-Application
来替代
Context-Activity
如果你不想控制内部类的生命周期,
应避免在
Activity
中使用非静态的内部类,
而应该使用静态的内部类,
并在其中创建一个对
Activity
的弱引用。
这种情况的解
决办法是使用一个静态的内部类,其中拥有对外部类的
WeakReference
,如同
ViewRoot
和它的
Winner
类那样
GC
(垃圾回收)不能解决内存泄露问题
相关文章推荐
- C#利用TcpListener和TcpClient类实现服务器和客户端的通信
- 字符串匹配算法--KMP算法
- 淘宝,京东,苏宁易购技术架构(路线)分析和比较
- Android FileObserver 实现原理(inotify)
- 十多家广州互联网公司的服务端面试经验
- smarty的section嵌套循环用法示例
- PetaPoco初体验(转)
- 动态创建的元素怎么做动画
- 设计模式学习笔记--抽象工厂模式
- hdu 1548 简单的bfs
- OpenCV下三对点计算仿射变换实现图像的水平镜像(翻转)的详细说明和源程序
- HDU 1016 Prime Ring Problem (DFS)
- Handler与Message
- redis消息发送与订阅
- gulp的使用
- tcpdump permission denied问题解决
- 框架模式 MVC 在Android中的使用
- 初学 android databinding
- 编程错误集
- Android开发技术问题收集