尝试在 phone 内存上写入时出现致命异常:java.lang.OutOfMemoryError

Fatal Exception when trying to write on phone memory: java.lang.OutOfMemoryError

这是完整的例外:

Fatal Exception: java.lang.OutOfMemoryError: Failed to allocate a 79386366 byte allocation with 16777216 free bytes and 75MB until OOM
   at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:95)
   at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:133)
   at java.lang.StringBuilder.append(StringBuilder.java:124)
   at ch.usi.jacopofidacaro.umob.background.RecordStorageManager.store(RecordStorageManager.java:156)
   at ch.usi.jacopofidacaro.umob.recordCommuter.RecordCommuter.storeLocally(RecordCommuter.java:76)
   at ch.usi.jacopofidacaro.umob.background.BackgroundRecorder.recordGyroscope(BackgroundRecorder.java:591)
   at ch.usi.jacopofidacaro.umob.background.BackgroundRecorder.run(BackgroundRecorder.java:139)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:148)
   at android.app.ActivityThread.main(ActivityThread.java:5417)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

这是它发生的地方:

public void store(Record record, String recordId, Context ctx, String recordType) {

    Log.i(STORE, "store():");

    // convert the POJO to JSON
    Gson gson = new Gson();
    String json = gson.toJson(record);

    String filePath = recordType + "_records";
    File file = new File(ctx.getFilesDir(), filePath);
    Log.i(STORE, "  target file: " + file.getAbsolutePath());


    Log.i(STORE, "  locally storing record: " + recordId);
    try {

        if (!file.exists()) file.createNewFile();
        FileWriter fw = new FileWriter(file.getAbsolutePath(), true);
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write(json);
        bw.close();

        FileReader fr = new FileReader(file.getAbsolutePath());
        BufferedReader br = new BufferedReader(fr);
        StringBuilder text = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null)
            text.append(line).append('\n');
        br.close();
        Log.i(STORE, "  record stored.");


    } catch (Exception e) {

        e.printStackTrace();

    }

}

简而言之,我正在读取陀螺仪传感器数据并将它们存储在名为 gyroscope_records 的本地文件中。每小时,我都会连接到 Firebase 以上传文件并在下一个小时开始写入新文件。在我看来,如果传感器读数太多并且文件变得非常大,则会发生此异常。但是,我不知道如何处理它。我怎样才能 read/write 大文件(如果这是这里的问题)?

您将不得不以某种方式将文件分解成更小的部分。您目前有一个将近 80MB 的文件,而且听起来它可能会变得更大。你的问题是你试图将整个文件读入内存,但你做不到。

几点建议:

  • 创建许多小文件。在这种情况下,我不知道 Record 有多大,但可能每分钟一个新文件或包含较少数量记录的文件。
  • 使用SQLite并将每条记录存储在数据库中。定期让另一个线程读出这些记录,发送它们,然后删除它们。
  • 仅附加到大文件。不要读入内存。

还有其他的可能性,但您无法将其全部保存在内存中。

我发现 StringBuilder“text”没有用处,但 text.append(...) 导致了异常。那么您是否尝试过将变量与 while 循环一起删除?