2012-10-28 10 views
4

我有兩個文件,包含字長度3至6和包含字7.字典的字典中的字存儲在文本文件用換行分離。此方法加載文件並將其插入到存儲在應用程序類中的ArrayList中。的Android插入字轉換爲ArrayList中,內存

的文件大小爲386KB和380 KB和包含各自小於200K字。

private void loadDataIntoDictionary(String filename) throws Exception { 
    Log.d(TAG, "loading file: " + filename); 
    AssetFileDescriptor descriptor = getAssets().openFd(filename); 
    FileReader fileReader = new FileReader(descriptor.getFileDescriptor()); 
    BufferedReader bufferedReader = new BufferedReader(fileReader); 
    String word = null; 

    int i = 0; 

    MyApp appState = ((MyApp)getApplicationContext()); 

    while ((word = bufferedReader.readLine()) != null) { 
     appState.addToDictionary(word); 
     word = null; 
     i++; 
    } 
    Log.d(TAG, "added " + i + " words to the dictionary"); 

    bufferedReader.close(); 
} 

程序在運行2.3.3的模擬器上使用64MB SD卡崩潰。 使用logcat報告的錯誤。 堆增長超過24 MB。然後我看到鉗位目標GC堆從25.XXX到24.000 MB。

GC_FOR_MALLOC釋放0K,12%空閒,外部1657k/2137K,暫停208ms。
GC_CONCURRENT釋放XXK,在一個24字節的分配免費
出的存儲器中,然後致命異常14%,存儲器耗盡。

我怎樣才能加載這些文件沒有得到如此大的堆?

內MyApp的:

private ArrayList<String> dictionary = new ArrayList<String>(); 
public void addToDictionary(String word) { 
    dictionary.add(word); 
} 
+0

你爲什麼這樣做:word = null? –

+0

我試圖確保gc知道釋放這個詞。我只是補充說,作爲最後的手段。 – user1781570

+0

請問您可以添加'addToDictionary()'函數的代碼嗎?這是尋找內存泄漏最明顯的地方。 –

回答

1

任何其他問題/錯誤的不管,ArrayList可以爲這種存儲的非常浪費,因爲越來越多的ArrayList運行的空間,雙打其底層的大小存儲陣列。所以有可能你的存儲將近一半被浪費了。如果您可以預先將存儲陣列或ArrayList的大小設置爲正確的大小,那麼您可能會大大節省。

此外(在偏執的數據清洗帽上)確保輸入文件中沒有額外的空白 - 如果需要,可以在每個單詞上使用String.trim(),或者先清理輸入文件。但我不認爲這可能是一個重要的問題,因爲你提到的文件大小。我記得你的輸入文件本身需要少於2MB的存儲空間(記住Java在內部使用UTF-16,所以通常每個字符需要2個字節),但String對象引用的開銷可能是1.5MB ,加上1.5MB的字符串長度開銷,並可能一次又一次地爲偏移量和散列碼(看看String.java)...而24MB的堆仍然聽起來有點過分,如果你正在一個不幸的ArrayList重新大小的倍增效果。

事實上,而不是猜測,如何測試?下面的代碼,與-Xmx24M運行變得至約560000 6個字符的字符串之前失速(在Java SE 7 JVM,64位)。它最終爬到了580,000左右(我想象中有很多GC抖動)。

ArrayList<String> list = new ArrayList<String>(); 
    int x = 0; 
    while (true) 
    { 
     list.add(new String("123456")); 
     if (++x % 1000 == 0) System.out.println(x); 
    } 

所以我不認爲有一個在你的代碼中的錯誤 - 存儲大量小弦的只是沒有Java的非常有效的 - 它上面的測試需要每個字符超過700字節,因爲所有的開銷(順便說一下,它可能在32位和64位機器上有所不同,並且也取決於JVM設置)!

通過存儲字節數組的數組,而不是String的ArrayList,可能會得到稍好的結果。還有更高效的數據結構來存儲字符串,例如Tries