【发布时间】:2016-11-07 21:28:30
【问题描述】:
使用 OkHttpClient 在 TC75(8mb 的 RAM)上解析 36972 行 JSON 响应时出现 java.lang.OutOfMemoryError。当我尝试调用 response.body().string()
时出现问题E/dalvikvm-heap: Out of memory on a 26525298-byte allocation.
我试图将数据保存在 StringBuilder 和流式 JsonReader 中,如 [in this answer here][1]
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(...).build();
try {
Response response = client.newCall(request).execute();
JsonReader jsonReader = new JsonReader(new StringReader(response.body().string()));
... (loads of JsonReader parsing)
} catch (IOException | ParseException e) {
e.printStackTrace();
}
在 Samsung S6 Active(3gb RAM)上运行时,应用程序可以轻松解析此 JSON。如何避免这种有限 RAM 的内存不足错误?有没有可能?
堆栈跟踪:
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
Process: com.at.project, PID: 4409
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:300)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.lang.OutOfMemoryError
at java.lang.String.<init>(String.java:255)
at java.lang.String.<init>(String.java:228)
at com.squareup.okhttp.ResponseBody.string(ResponseBody.java:83)
at com.at.project.activities.LoginNewActivity$UserLoginTask.getOEMPartPricingJson(LoginNewActivity.java:1496)
at com.at.project.activities.LoginNewActivity$UserLoginTask.downloadAnyNewJson(LoginNewActivity.java:860)
at com.at.project.activities.LoginNewActivity$UserLoginTask.checkForatDprojectdates(LoginNewActivity.java:746)
at com.at.project.activities.LoginNewActivity$UserLoginTask.checkForUpdates(LoginNewActivity.java:659)
at com.at.project.activities.LoginNewActivity$UserLoginTask.doInBackground(LoginNewActivity.java:486)
at com.at.project.activities.LoginNewActivity$UserLoginTask.doInBackground(LoginNewActivity.java:465)
at android.os.AsyncTask$2.call(AsyncTask.java:288)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
【问题讨论】:
-
请发布与您的问题中的代码相关联的完整 Java 堆栈跟踪。我可以看到
OutOfMemoryError用于response.body().string()场景。您暗示您的JsonReader代码不起作用,但您没有说明该代码存在什么问题。 -
JsonReader 代码与 StringBuilder 代码存在相同的问题,即在 response.body().string() 调用时内存不足。这是堆栈跟踪。我将使用堆栈跟踪编辑原始帖子。
-
您的堆栈跟踪显示您在
ResponseBody上调用了string()。您问题中的源代码不在ResponseBody上调用string()。您问题中的源代码在ResponseBody上调用charStream()。请发布完整的 Java 堆栈跟踪与您的问题中的代码相关联,显示您对JsonReader和charStream()的使用。 -
抱歉,charStream() 调用是一个错字。这会引发错误,因为它会在 StringReader 的构造函数中返回 Stream。
-
对于这种大小的 JSON 文件,您会收到带有
string()的OutOfMemoryError,我并不感到非常惊讶。您正在尝试将整个 JSON 文件一次性读入内存,这在大多数设备上都不起作用。直接使用charStream()应该会更好。因此,您应该考虑详细解释“无济于事”的含义。