2012-03-22 56 views
12

我正在退出內存錯誤。我正在開發實時聊天應用程序。它工作正常,但是當我在設備上運行應用程序1到2小時時,堆大小正在增加,當它達到16 MB時,應用程序開始掛起並在一段時間後崩潰,並顯示out of memory due to heap size,因爲結果堆大小大於分配。由於堆大小增加,在android中出現內存不足錯誤

我在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) 

堆大小是否有限制?我如何解決我的問題?

+1

發表一些代碼。我的猜測是你在自定義列表中使用大的位圖。 – Venky 2012-03-22 08:06:41

+0

...還是大陣? – 2012-03-22 08:07:46

+0

我沒有在我的application.i中使用位圖在可繪製的文件夾中有一些圖像,我只使用它們,這些圖像的數量並不多,15到20個圖像都有。 – nikki 2012-04-24 10:15:45

回答

11

您的問題有兩個部分:

1)如何確定測試設備上堆的大小?

2)爲什麼我的應用程序超過了堆的大小?

關於問題1,可以通過調用直接確定堆的大小在測試設備上在代碼:

調用Runtime.getRuntime()maxMemory();

請參閱this post瞭解有關該方法的更多信息,以及各種設備上可用的堆大小示例。

此外,如果您運行的是根設備,則可能有一種方法可以通過該接口直接設置(並檢查)堆大小。例如,在CyanogenMod的各種Android版本中,您可以從設置菜單中選擇「CyanogenMod設置」,然後選擇「性能」,然後選擇「虛擬機堆大小」,然後直接查看(並更改)設備的堆大小。要小心,因爲將堆的大小設置得太小可能會使您的設備不當或更糟。

關於問題2:您沒有提供足夠的信息來診斷您的具體問題,並且在任何情況下,二手診斷都很困難。解決此問題(以及學習過程中持久價值的東西)的最佳選擇是熟悉Android中可用的一些非常強大的內存分析工具(其中一些還集成到Eclipse IDE中)。我從Eclipse中使用這些工具,所以這就是我將在下面描述的內容。

首先,通過安裝最新版本的Eclipse(例如Indigo)來確保您的Eclipse版本是最新版本。

接下來,在Eclipse中,選擇幫助/安裝新軟件,然後單擊下拉列表頂部,並選擇

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

接下來,點擊旁邊的加號打開通用工具類,並選擇內存分析器和內存分析器(圖表)[可選]。安裝這些工具。

接下來,選擇Window/Preferences,然後選擇Android/DDMS,然後選擇HPROF操作爲「在Eclipse中打開」。這將導致您從DDMS生成的任何HPROF堆轉儲文件成爲適用於Eclipse的格式,並且還會導致它在Eclipse的內存分析器(它剛安裝在上面)中自動打開。

現在,通過選擇Window/Open Perspective/Other/DDMS來打開DDMS。選擇左側的設備圖標(看起來像電話),然後拖動窗口,使其停靠在可以輕鬆看到的地方。

確保您的設備通過USB連接到PC,並且您的應用程序正在運行。

在剛剛創建的設備選項卡中,選擇正在運行的應用程序的進程。運行應用程序到它已經佔用足夠的內存,你知道它已經泄漏,但沒有太多,它崩潰。現在,單擊設備選項卡中的轉儲HPROF文件圖標。在短暫的延遲之後,您將會收到關於堆的報告選擇。嘗試泄漏可疑報告開始。該報告將在內存分析工具中打開。它會告訴你你的應用程序在哪裏使用內存。檢查各種對象,看看它們是否顯得相對於您期望它們需要的數據量而言臃腫;如果是這樣,那可能表明泄漏。

Here是一個很好的教程,更詳細地描述如何使用DDMS和內存分析工具生成和探索堆。

回到DDMS(或Eclipse中的DDMS透視圖),您可以在設備連接時選擇Allocation Tracker選項卡,然後從設備選項卡選擇設備,然後從該設備的列表中選擇應用程序的進程。然後,在分配跟蹤器選項卡中,單擊開始跟蹤按鈕,然後運行應用程序的相關操作(那些您懷疑正在泄漏的操作),然後單擊獲取分配按鈕,然後選擇停止跟蹤按鈕。

這將顯示您在跟蹤時發生的所有分配(存儲金額的限制)。點擊其中的任何一個會在分配時將您帶到堆棧,然後單擊堆棧轉儲的任何部分都會將您帶到分配中涉及的源代碼。

這些工具應該讓你瞭解什麼可能會導致你的應用程序泄漏內存。

+0

謝謝捲曲.............. ....... – nikki 2012-05-09 11:50:00

1

堆大小限制取決於設備。在2.x設備上,我預計約有20或32 MB是您的限制。有關堆大小的更多信息,請參閱Android heap size on different phones/devices and OS versions

從您的堆棧跟蹤中,它看起來像com.live2support.CustomHttpClient.executeHttpPost1()是您的問題的中心。

+0

那我能做些什麼? – nikki 2012-05-02 07:24:47

+0

通常的東西。我會按以下順序嘗試:1.對代碼進行視覺檢查。也可以在SO上添加你的功能來解決這個問題,這樣其他人就可以檢查出來。 2.使用源代碼級別的調試程序遍歷代碼。 3.使用DDMS如果2不行。 http://developer.android.com/guide/developing/debugging/ddms.html – Sparky 2012-05-02 07:30:56

7

它看起來像一個經典的內存泄漏。你說,你使用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錯誤。

如果你確定你有這種內存泄漏,你應該做的是安裝MAT for Eclipse,學習如何使用它(與上述電影),並找出它的原因。

我個人認爲是AsyncTask的一個不好的實現 - 你是否將它從已銷燬的Activity中分離出來並附加到新的Activity上?如果沒有,開始這樣做(CommonsWare有一個很好的例子),或者切換到AsyncTaskLoader,它可以替代AsyncTask(不僅用於加載內容)。

+0

另外我有一個奇怪的問題,只有當我從調試器啓動我的應用程序時纔出現OOM錯誤。當啓動正常與啓動器圖標內存泄漏沒有發生:http://stackoverflow.com/questions/10305037/leaking-memory-with-actionbarsherlock – 2012-05-02 08:00:44

0

根據你的Android操作系統,這可以通過兩種方式完成。

  1. 您可以在Android清單的應用程序標籤中使用android:largeHeap="true"來請求更大的堆大小,但這不適用於任何預蜂窩設備。
  2. 在2.3之前的設備上,您可以使用VMRuntime類,但這不適用於薑餅和以上請參閱下面的操作方法。
VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE); 

設置HEAPSIZE確保你已經進入了適當的大小,這將不會影響其他應用程序或操作系統的功能之前。在設置之前,請檢查您的應用需要多少尺寸,然後設置尺寸才能完成您的工作。不要使用太多的內存,否則其他應用程序可能會受到影響。

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

4

只需在應用程序標記你的清單中添加android:largeHeap="true"

+3

雖然這段代碼可能會回答這個問題,但提供關於如何解決問題和/或爲什麼解決問題的附加環境會提高答案的長期價值。 – mech 2016-02-26 06:48:20

相關問題