上一篇文章总结了一下内存分析的方法,这次聊聊如何出现解决和避免内存相关的问题。
上一篇文中我们提到,出现OOM通常是因为有内存泄漏或是内存使用不当(分配了过多的内存),在Android的早期时代,内存真是非常的珍贵啊,大部分是手机只有32或24M的heapsize,记得曾经有一个项目,有图片处理的逻辑,运行几分种就会OOM,很多人就说是有内存泄露,后来排查了半天,发现是处理的速度跟不上加载的速度,消耗了太多的内存导致,现在主流的手机heapsize基本上都有64M,应该来讲,只要没有内存泄漏,很少会发生OOM的,并且,从Android 3.0开始,引入了largeheap,就是说你在manifest的application TAG中加入 android:largeHeap="true" 之后就可以让你的应用申请更多的内存(每个手机定义的大小不尽相同),标准的heapsize和largeHeap都可以通过方法查询的到:
ActivityManager mgr = (ActivityManager) MainActivity.this
.getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "MemoryClass is:"+mgr.getMemoryClass()+",large class is:"+mgr.getLargeMemoryClass());
你的应用到底有多少的heapsize可以通过:
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
来获取(注意,这里的单位是K)
我测试了几个手机,Galaxy nexus 可以申请到256M的heapsize,256M啊,同学们,这是多么的奢侈啊,但是人家谷歌说的很清楚,用这个标签一定要慎重,除非你是真的需要这么多内存,不能把这玩意作为快速解决OOM的手段,如果你的内存使用过多,还是先慎重的分析一下你的内存到哪里去了,因为这会导致GC的时间较长并且会影响系统的性能,原文如下:
However, the ability to request a large heap is intended only for a small set of apps that can justify the need to consume more RAM (such as a large photo editing app). Never request a large heap simply because you've run out of memory and you need a quick fix—you should use it only when you know exactly where all your memory is being allocated and why it must be retained. Yet, even when you're confident your app can justify the large heap, you should avoid requesting it to whatever extent possible. Using the extra memory will increasingly be to the detriment of the overall user experience because garbage collection will take longer and system performance may be slower when task switching or performing other common operations
无论手机的内存有多大,请记住,这只是手机,一定要珍惜内存。
那怎么样能够减少内存的使用呢,我个人认为,可以从以下几个方面入手:
- 避免内存泄漏
- 能不创建的对象就不要创建
- 合理管理对象生命周期
- 科学设计应用背景图片(尽量使用.9.png图片)
避免内存泄漏
首先是一定要避免内存泄漏,如果存在内存泄漏,多少内存也不够用,关于Java为什么会有内存泄漏以及内存泄露的定义IBM网站上有一篇文章说的非常到位:http://www.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/
这里摘录一下该文的重点:
在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对 象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占 用内存。
GC是如何工作的呢:
文章也很好的交代了这一点:
为了更好理解GC的工作原理,我们可以将对象考虑为有向图的顶点,将引用关系考虑为图的有向边,有向边从引用者指向被引对象。另外,每个线程对象可 以作为一个图的起始顶点,例如大多程序从main进程开始执行,那么该图就是以main进程顶点开始的一棵根树。在这个有向图中,根顶点可达的对象都是有 效对象,GC将不回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。
这些问题阐述清楚之后我们来看看Android平台常见的导致内存泄漏的原因(基本上都是在以往的项目中碰到的):
1.registerContentObserver未解注册(观察者模式要小心,切记适时解注册);
2.没有关闭(一定要在finally中关闭)cursor,这里要多说一点的是,我们其实可以用AsyncQueryHandler或者CursorLoader 等数据库异步加载框架避免在activity中对cursor的管理;
3.Adapter bindview实现不当,这个属于比较低级的,但是还是有人会这么干,就是在bindview里不去判断convertview直接创建,关于怎么实现这里不再多讲;
4.单例模式注册listener未解注册;
5.mTelePhonyMgr.listen(mListener,PhoneStateListener.LISTEN_NONE);貌似这么调用之后不能解注册,不知道4.0以后的版本有没有修改。
大部分的问题都跟static有关,一旦声明成static,除非我们主动的设置为null,否则是无法被回收的,像单例,观察者这些设计模式,通常都有生命周期较长的一方,使用的时候一定要小心。
能不创建的对象就不要创建
其实很多时候我们一个不小心的举动就会创建过多的对象,比如下面的这段代码:
public class DataBean {
private String mData = "";
private ArrayList<DataB> mDataBs = new ArrayList<DataB>();
}
这就是很不好的编程习惯,如果这些字段为空,就无端的多创建了很多的对象,如果我们在内存中又加载了大量这样的对象,。。。。浪费啊。
再比如说,通常我们有一些比较复杂的界面,布局文件会比较庞大,常常会通过逻辑的需要来控制不同元素的可见性,这时候如果我们采用viewstub,在需要的时候再加载相应的布局,就可以避免创建无用的对象,也可以加快activity的加载速度。:
写道
<ViewStub android:id="@+id/stub"
android:inflatedId="@+id/subTree"
android:layout="@layout/mySubTree"
android:layout_width="120dip"
android:layout_height="40dip" />
另外,有时候我们可以通过复用对象来达到少创建对象的目地,比如当我们有大量的数据需要插入到数据库时,
我们就可以这么做:
private ContentValues mValues = new ContentValues();
public void inserVaules(String value1,int vaule2){
mValues.clear();
mValues.put(key, value1);
mValues.put(key, vaule2);
this.getContentResolver().insert(url, values);
}
合理管理对象生命周期:
这个通常在架构阶段就要考虑清楚,我们有哪些东西是要常驻内存的,有哪些是伴随界面存在的,尤其是那些缓存和业务逻辑层的manager,在做缓存的时候一定要平衡好内存和性能,关于一些缓存资源的释放推荐看一下Android新引入的onTrimMemory() 方法,目前源码中已经有部分的逻辑实现了该方法
比如系统luncher中:
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
mAppsCustomizeTabHost.onTrimMemory();
}
}
public void onTrimMemory() {
mContent.setVisibility(GONE);
// Clear the widget pages of all their subviews - this will trigger the widget previews
// to delete their bitmaps
mAppsCustomizePane.clearAllWidgetPages();
}
AppsCustomizePagedView.java
public void clearAllWidgetPages() {
cancelAllTasks();
int count = getChildCount();
for (int i = 0; i < count; i++) {
View v = getPageAt(i);
if (v instanceof PagedViewGridLayout) {
((PagedViewGridLayout) v).removeAllViewsOnPage();
mDirtyPageContent.set(i, true);
}
}
}
private void cancelAllTasks() {
// Clean up all the async tasks
Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
while (iter.hasNext()) {
AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
task.cancel(false);
iter.remove();
mDirtyPageContent.set(task.page, true);
// We've already preallocated the views for the data to load into, so clear them as well
View v = getPageAt(task.page);
if (v instanceof PagedViewGridLayout) {
((PagedViewGridLayout) v).removeAllViewsOnPage();
}
}
mDeferredSyncWidgetPageItems.clear();
mDeferredPrepareLoadWidgetPreviewsTasks.clear();
}
科学设计应用背景图片
这个不用做过多的阐述,凡事都是有代价的,太炫太复杂太大太多的背景图片会导致应用耗用过多的内存。
另外,谷歌也给出了一些节省内存的tips:
比如stringbuffer啊,尽量用int基本类型而不是Integer等。
分享到:
相关推荐
### Android内存管理知识点总结 #### 一、Dalvik虚拟机及其优势 - **Dalvik虚拟机简介**:Dalvik虚拟机是Android系统的核心组件之一,它负责执行Android应用中的Java字节码。与传统的Java虚拟机(JVM)不同,Dalvik...
以下是关于Android内存管理的深入解析: 1. **进程分类**: - **前台进程(Foreground)**:正在用户交互界面中显示或关键系统进程,如Dialer、Storage、Google Search等,具有最高优先级,一般不会被系统自动结束...
在Android应用开发中,内存管理是一项至关重要的任务,因为它直接影响到应用的性能、稳定性和用户体验。内存监控工具能够帮助开发者检测和分析应用的内存使用情况,预防和解决内存泄漏等问题。"Emmagee.apk"可能是一...
二维码简介及Android 内存管理 MAT内存分析工具
此外,多篇学术文献和技术报告也对Android系统的内存管理进行了研究和讨论,相关专业指导和参考文献也在不断增多,这为Android系统开发人员提供了丰富的学习资源和实践案例。通过不断地研究和探索,可以更好地应对...
本篇文章将深入探讨Android内存管理的两个核心概念:堆(Heap)和栈(Stack),以及如何理解和解决Android内存溢出问题。 1. 堆与栈 堆和栈是Java虚拟机(JVM)中的两种主要内存区域,它们各自具有特定的用途和...
Android内存管理机制研究 Android内存管理机制是Android操作系统的核心组件之一,负责管理和分配移动设备的内存资源。Android内存管理机制研究是移动应用开发者和研究人员需要深入了解和掌握的知识领域。本文将深入...
Android内存管理是操作系统核心部分,它负责有效地分配和回收设备上的内存资源,以确保应用程序能够稳定、高效地运行。在Android系统中,内存管理采用了独特的策略,与传统的Linux内核有所不同,尤其体现在Low ...
总之,虽然Java的垃圾回收机制为内存管理提供了一定的便利,但Android应用开发者仍然需要注意正确管理内存,以避免内存泄漏的发生。通过学习和实践上述知识点,开发者可以提高编写高效且稳定的应用程序的能力。
android内存管理机制分析,帮助你了解内存管理原理,更好的开发程序
在Android开发中,内存泄漏是一个严重的问题,它会导致应用程序占用过多内存,影响性能甚至导致应用崩溃。本示例代码着重展示了如何避免Android应用中的内存...记住,良好的内存管理是提升应用性能和稳定性的重要因素。
### Android内存泄露测试详解 在Android开发中,内存管理是一项至关重要的任务,不当的内存管理会导致应用运行...例如,参考文章《Android在测试中的应用》([...,可以获取更多关于Android内存管理和测试的实用技巧...
高FPS是保证游戏流畅性的关键,而内存管理则直接影响了游戏的稳定性和资源效率。监控和控制内存占用有助于预防因内存泄漏导致的游戏卡顿或崩溃。通过Unity与Android的交互,开发者可以实时获取性能指标,及时调整...
在Android开发中,内存管理是至关重要的,因为它直接影响到应用的性能、稳定性和用户体验。本文将详细介绍如何使用各种工具进行内存管理,特别是MAT(Memory Analyzer Tool)的使用方法,并探讨防范内存溢出的有效策略...
综上所述,胡凯提出的Android内存优化的5R法则,结合了内存管理的基础知识,为Android应用的内存优化提供了一套全面的策略。开发者在实际开发过程中应该深入理解并灵活运用这些法则,以达到更佳的应用性能。
理解Android的内存管理机制和熟练使用这些工具,是提高应用性能和稳定性的重要一环。定期进行性能测试和内存分析,可以帮助开发者发现并修复潜在的问题,提升用户体验。记住,良好的编程习惯和对内存管理的深入理解...