Android 踏雷日記(1)String Out Of Memory

本文记录了在Android开发中遇到的一个由于大量使用String导致的内存溢出问题。详细探讨了String对象的内存分配、常量池以及垃圾回收机制,并提供了优化建议和解决方案,帮助开发者避免类似的内存陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在開發字典查詢 App 的時候發生了檔案讀出來存成 buffer 後, 再轉成 String 的過程中發生 Out Of Memory, 一直在百思不解的情況下上社群問了解法, 得到的結果是在 AndroidManifast.xml 的 <applicaton> 標籤加入 android:largeHeap="true" 屬性解決, 可是有些手機卻不用就能夠正常執行, 到底是發生了什麼原因呢?讓我們來還原現場吧!

還原現場步驟:

  1. 環境介紹
  2. 把檔案放到 Assess 裡面
    把檔案放到 Assess 裡面
  3. 在 Activity 把這個檔案讀出來並轉成 String
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    AssetManager assetManager = getAssets();
    InputStream ims = assetManager.open( "dict.json" );
    int size = ims.available();
    byte [] buffer = new byte [size];
    ims.read(buffer);
    ims.close();
    // 41175344
    System.out.println(buffer.length);
    // java.lang.OutOfMemoryError
    String s = new String(buffer);
  4. 執行後就會發生 Out Of Memory
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    7975 AndroidRuntime E FATAL EXCEPTION: main
    7975 AndroidRuntime E java.lang.OutOfMemoryError
    7975 AndroidRuntime E at java.lang.String.<init>(String.java: 255 )
    7975 AndroidRuntime E at java.lang.String.<init>(String.java: 171 )
    7975 AndroidRuntime E at java.lang.String.<init>(String.java: 141 )
    7975 AndroidRuntime E at org.im.sundictionary.MainActivity.onCreate(MainActivity.java: 66 )
    7975 AndroidRuntime E at android.app.Activity.performCreate(Activity.java: 5133 )
    7975 AndroidRuntime E at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java: 1087 )
    7975 AndroidRuntime E at android.app.ActivityThread.performLaunchActivity(ActivityThread.java: 2175 )
    7975 AndroidRuntime E at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java: 2261 )
    7975 AndroidRuntime E at android.app.ActivityThread.access$ 600 (ActivityThread.java: 141 )
    7975 AndroidRuntime E at android.app.ActivityThread$H.handleMessage(ActivityThread.java: 1256 )
    7975 AndroidRuntime E at android.os.Handler.dispatchMessage(Handler.java: 99 )
    7975 AndroidRuntime E at android.os.Looper.loop(Looper.java: 137 )
    7975 AndroidRuntime E at android.app.ActivityThread.main(ActivityThread.java: 5103 )
    7975 AndroidRuntime E at java.lang.reflect.Method.invokeNative(Native Method)
    7975 AndroidRuntime E at java.lang.reflect.Method.invoke(Method.java: 525 )
    7975 AndroidRuntime E at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java: 737 )
    7975 AndroidRuntime E at com.android.internal.os.ZygoteInit.main(ZygoteInit.java: 553 )
    7975 AndroidRuntime E at dalvik.system.NativeStart.main(Native Method)

分析現場

現場還原了, 但是還是不知道兇手是怎麼樣殺死我的 App 的阿!! 原來是每個手機中各自的 App 可以使用的記憶體上限不同, 也就是有些手機可能是 96M, 而有一些則是 20M.

我們可以透過下面這段程式來瞭解自己手機每個 App 記憶體使用量上限是多少:

1
2
3
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int mMemoryClass = am.getMemoryClass();
long mLargeMemoryClass = am.getLargeMemoryClass();

而 android:largeHeap="true" 就是告訴系統這個 App 使用量可能會比較大, 請放寬限制!!

什麼!2.3.3 不支援 android:largeHeap="true" ?

雖然現在都是 Android 4.x 居多的時代, 但抱持著研究的精神當然還是得解決 2.3.3 的問題, 現在讓我們來一步一步解決問題吧.

  1. 建立 2.3 專用的 values 資料夾
    5481dc386da05
    建立 2.3 專用的 values 資料夾
  2. 在 values-v14 下建立 bool.xml
    5481dc387e2d7
    在 values-v14 下建立 bool.xml
  3. 在 bool.xml 加入 <bool name="largeheap">true</bool>
    bool.xml 檔案內容如下:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <bool name="largeheap">true</bool>
    </resources>
  4. 在 AndroidManifst.xml 加入 android:largeHeap="@bool/largeheap"
  5. 大功告成啦!!

參考文獻

補充

那 largeHeap 的上限到底怎麼設定進去的呢? 那就得看一下 system 的設定檔, 如果你的裝置是 root 就可以使用下面的指令:

1
adb pull /system/build.prop [指定路徑]

接著打開 build.prop 然後跳到 85 行, 就可以看見你這個裝置的 hepap 的相關設定啦!

54812a0b33b67

如果有興趣也可以看看 system 在 build 的時候的設定檔唷~
https://github.com/android/platformframeworksbase/blob/master/core/jni/AndroidRuntime.cpp#L655

有趣的小發現

在研究的過程竟然發現有人做了一個可以編輯 build.prop 的 App, 作者我就沒有玩過了, 請勇者們去嘗試吧!!

https://play.google.com/store/apps/details?id=org.nathan.jf.build.prop.editor&hl=zh_HK

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值