由于堆大小增加,android中的内存不足错误

Posted

技术标签:

【中文标题】由于堆大小增加,android中的内存不足错误【英文标题】:Out of Memory Error in android due to Heap Size Increasing 【发布时间】:2012-04-06 18:51:24 【问题描述】:

我正在摆脱内存错误。我正在开发实时聊天应用程序。它工作正常,但是当我在设备上运行应用程序 1 到 2 小时时,堆大小正在增加,当它达到 16 MB 时,应用程序开始挂起并在一段时间后崩溃并显示out of memory due to heap size,因为生成的堆大小是大于分配。

我正在 HTC Explorer 上测试我的应用程序。在我的应用程序中,大多数活动都使用后台线程,为此我使用的是 Asnyc Task。

我收到如下错误。

04-30 16:53:14.658: E/androidRuntime(5707): FATAL EXCEPTION: MagentoBackground
04-30 16:53:14.658: E/AndroidRuntime(5707): java.lang.OutOfMemoryError: (Heap Size=20167KB, Allocated=16063KB, Bitmap Size=355KB)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.util.ByteArrayBuffer.<init>(ByteArrayBuffer.java:53)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:82)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:98)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:173)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:359)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
04-30 16:53:14.658: E/AndroidRuntime(5707):     at com.live2support.CustomHttpClient.executeHttpPost1(CustomHttpClient.java:163)

堆大小有限制吗?我该如何解决我的问题?

【问题讨论】:

发布一些代码。我的猜测是您在自定义列表中使用大型位图。 我没有在我的应用程序中使用位图。我在可绘制文件夹中有一些图像,我只使用它们,而不是我拥有的 15 到 20 张图像。 您是否真的需要运行时的所有聊天历史记录,或者您将这些聊天记录保存在数组或集合对象中,或者您的列表视图太大。您可以使用动态增长的列表视图。 在 com.live2support.CustomHttpClient.executeHttpPost1(CustomHttpClient.java:163) - 你正在做的事情每次都会占用大量内存..尝试释放内存,一旦你使用它..甚至在任何地方,只要你使用它,对象、数组列表、位图就会从内存中清除。一旦使用分配 null 并调用 System.gc();向垃圾收集器指示标志。 是的,我正在调用 System.gc();无处不在。 【参考方案1】:

您的问题分为两部分:

1) 如何确定测试设备上的堆大小?

2) 为什么我的应用超出了我的堆大小?

关于问题 1,您可以通过调用直接在代码中确定测试设备上的堆大小:

Runtime.getRuntime().maxMemory();

有关该方法的更多信息以及各种设备上可用的一些示例堆大小,请参阅this post。

另外,如果您正在运行一个根设备,可能有一种方法可以通过接口直接设置(和检查)堆大小。例如,在 CyanogenMod 的各种 Android 版本中,您可以从设置菜单中选择“CyanogenMod 设置”,然后选择“性能”,然后选择“VM 堆大小”,并直接查看(和更改)您设备的堆大小.请小心,因为将堆大小设置得太小可能会使您的设备行为异常或更糟。

关于问题 2:您没有提供足够的信息来诊断您的具体问题,无论如何,做这样的二手诊断充其量是困难的。解决这个问题(以及在此过程中学习一些具有持久价值的东西)的最佳选择是熟悉 Android 中可用的一些非常强大的内存分析工具(其中一些也集成到 Eclipse IDE 中)。我使用 Eclipse 中的这些工具,这就是我将在下面描述的内容。

首先,通过安装最新版本的 Eclipse(例如 Indigo)确保您的 Eclipse 版本是最新的。

接下来,在Eclipse中,选择Help/Install New Software,然后点击顶部的下拉菜单并选择

"Indigo - http://download.eclipse.org/releases/indigo"

接下来,通过单击旁边的加号打开通用工具类别,然后选择内存分析器和内存分析器(图表)[可选]。安装这些工具。

接下来,选择 Window/Preferences,然后选择 Android/DDMS,并将 HPROF 操作选择为“Open in Eclipse”。这将导致您从 DDMS 生成的任何 HPROF 堆转储文件具有适合 Eclipse 的格式,并且还会导致它在 Eclipse 的内存分析器(刚刚安装在上面)中自动打开。

现在,通过选择 Window/Open Perspective/Other/DDMS 打开 DDMS。选择左侧的设备图标(看起来像电话)并拖动生成的窗口,使其停靠在您可以轻松看到的位置。

确保您的设备已通过 USB 连接到 PC,并且您的应用正在运行。

在您刚刚创建的“设备”选项卡中,选择正在运行的应用程序的进程。运行应用程序,直到它占用了足够的内存,你知道它已经泄漏了,但还没有到崩溃的程度。现在,单击设备选项卡中的转储 HPROF 文件图标。短暂延迟后,您将可以选择堆上的报告。尝试泄漏嫌疑人报告以开始。此报告将在内存分析工具中打开。它告诉你你的应用在哪里使用内存。检查各种对象,看看它们相对于您期望它们需要的数据量是否显得臃肿;如果是这样,则可能表明存在泄漏。

Here 是一个很好的教程,更详细地描述了如何使用 DDMS 和内存分析器工具生成和探索堆。

返回 DDMS(或 Eclipse 中的 DDMS 透视图),您可以在连接设备时选择 Allocation Tracker 选项卡,然后从设备选项卡中选择您的设备,然后从该设备的列表中选择您的应用程序进程。然后,在 Allocation Tracker 选项卡中,单击 Start Tracking 按钮,然后运行您应用的相关操作(您怀疑泄漏的操作),然后单击 Get Allocations 按钮,然后选择 Stop Tracking 按钮。

这将显示您在跟踪时发生的所有分配(它将存储的数量有限制)。单击其中任何一个将带您进入分配时的堆栈,单击该堆栈转储的任何部分将带您进入分配所涉及的源代码。

这些工具可以让您深入了解可能导致您的应用内存泄漏的原因。

【讨论】:

【参考方案2】:

它看起来像一个经典的内存泄漏。您说,您使用AsyncTask 进行连接。当您不知道如何正确使用 AsyncTask 时,很容易在配置更改(例如设备旋转)时泄漏上下文。

第一件事 - 我强烈建议您观看:http://www.youtube.com/watch?v=_CruQY55HOk

要检查您是否有此类内存泄漏,请旋转您的设备并检查垃圾收集器的行为方式。几乎每次旋转时,您的 LogCat 中都应该有类似 GC_... freed 211K, 71% free 300K/1024K, external 0K/0K, paused 1ms+1ms 的内容。注意这部分的变化:300K/1024K。如果您没有内存泄漏,那么第一部分应该会在几次 GC 后增长然后变小。如果你有内存泄漏,它会越来越大,直到 OOM 错误。

如果你确定你有这种方式的内存泄漏,你应该做的是为 Eclipse 安装 MAT,学习如何使用它(通过上述电影)并找出它的原因。

我个人认为 AsyncTask 的实现会很糟糕——你是否将它从已销毁的 Activity 中分离出来并将其附加到新的 Activity 上?如果没有,请开始做(CommonsWare 有一个很好的例子)或切换到 AsyncTaskLoader,它会为您做这件事,通常是 AsyncTask 的一个很好的替代品(不仅用于加载东西)。

【讨论】:

我也遇到了一个奇怪的OOM错误问题,只有当我从调试器启动我的应用程序时才会出现。当使用启动器图标正常启动时,不会发生内存泄漏:***.com/questions/10305037/…【参考方案3】:

只需在清单中的应用程序标记中添加android:largeHeap="true"

【讨论】:

虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。【参考方案4】:

您的堆大小限制取决于设备。在 2.x 设备上,我预计大约 20 或 32 MB 是您的限制。有关堆大小的更多信息,请参阅 Android heap size on different phones/devices and OS versions。

从您的堆栈跟踪来看,com.live2support.CustomHttpClient.executeHttpPost1() 似乎是您问题的中心。

【讨论】:

普通的东西。我会按以下顺序尝试: 1. 对代码进行目视检查。也可以在 SO 将您的功能添加到此问题中,以便其他人可以查看。 2. 使用源级调试器单步调试代码。 3. 如果 2 不能解决问题,请使用 DDMS。 developer.android.com/guide/developing/debugging/ddms.html【参考方案5】:

这可以根据您的 Android 操作系统通过两种方式完成。

    您可以在 Android 清单的应用程序标记中使用 android:largeHeap="true" 来请求更大的堆大小,但这不适用于任何预 Honeycomb 设备。 在 2.3 之前的设备上,您可以使用 VMRuntime 类,但这不适用于 Gingerbread 及更高版本,请参阅下文。
VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE);

在设置 HeapSize 之前,请确保您已输入适当的大小,不会影响其他应用程序或操作系统的功能。在设置之前,只需检查您的应用需要多少大小,然后设置大小以完成您的工作。不要使用太多内存,否则可能会影响其他应用程序。

参考:http://dwij.co.in/increase-heap-size-of-android-application

【讨论】:

以上是关于由于堆大小增加,android中的内存不足错误的主要内容,如果未能解决你的问题,请参考以下文章

Eclipse 堆空间(内存不足错误)

增加堆以避免 WEKA 中的内存不足错误

如何增加 STS(Spring Tool Suite)内存大小?

内存不足:添加 10KB ImageButtons 后出现堆大小错误

内存不足错误发生在堆大小高但分配大小低的情况下。为啥?

如何永久增加java堆内存?