OutOfMemoryError: Failed to allocate when paging through responses
OutOfMemoryError: Failed to allocate when paging through responses
我收到以下 OutOfMemoryError 异常尝试翻阅来自 API
的响应
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 37748744 byte allocation with 25165824 free bytes and 24MB until OOM, target footprint 268261936, growth limit 268435456
at java.util.Arrays.copyOf(Arrays.java:3257)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:649)
at java.lang.StringBuilder.append(StringBuilder.java:203)
at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.readAll(INatCall.java:105)
at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:56)
at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75)
at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75)
at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75)
at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.doInBackground(INatCall.java:42)
有没有更有效的方法通过rest处理大量数据?
我的应用程序调用 API,returns 用户的 'entries'。 API 的最大页数是 200。大多数用户将有超过 200 个条目,这对大部分人来说都很好。我的应用程序可以分页并说明这一点。但是,有些用户将拥有 +2000 个条目,而我的应用程序 运行 内存不足,试图遍历这些较大的集合。
我的问题是:
- 有没有办法增加我的 android 应用程序的内存量
使用?
- 有哪些方法可以优化以下代码以减少使用
内存?
递归休息调用
private JSONArray restCall(URL url, JSONArray results) {
Log.d(TAG, "restCalliNat: Start");
InputStream is = null;
int totalResults = 0;
int perPage = 0;
JSONArray newResults = new JSONArray();
try {
is = url.openStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd); //<-- LINE 56
is.close();
rd.close();
JSONObject json = new JSONObject(jsonText);
newResults = json.getJSONArray("results");
totalResults = (int) json.get("total_results");
perPage = (int) json.get("per_page");
} catch (IOException | JSONException e) {
e.printStackTrace();
return null;
}
if (results != null) {
newResults = concatArray(results, newResults);
}
if (totalResults > page*perPage) {
newResults = restCall(updatePageCount(url), newResults);
}
return newResults;
}
在每个新页面上,新页面都会连接起来,直到我拥有所有条目。
private JSONArray concatArray(JSONArray arr1, JSONArray arr2) {
JSONArray result = new JSONArray();
try {
for (int i = 0; i < arr1.length(); i++) {
result.put(arr1.get(i));
}
for (int i = 0; i < arr2.length(); i++) {
result.put(arr2.get(i));
}
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
将 API 响应转换为字符串
private static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp); //<--- LINE 105
}
return sb.toString();
}
and my app is running out of memory
这与错误所说的不完全相同:Caused by: java.lang.OutOfMemoryError: Failed to allocate a 37748744 byte allocation with 25165824 free bytes and 24MB until OOM
。您有 24MB 的可用内存。但是,您正在尝试分配一个 36MB 的单个缓冲区,但这是行不通的。即使您有 124MB 或 524MB 的空闲内存,您也可能无法访问单个 36MB 的连续空闲内存块。
Converts API response to String
任一:
- 一次从您的 REST Web 服务请求更少的项目(而不是 200,尝试 5);或
- 停止尝试将整个 API 响应读入字符串,因为您的 API 响应非常大
您可能想尝试更现代的解决方案来访问 REST 样式的 Web 服务。例如,Retrofit 相当流行,不需要您将整个原始 JSON 读入单个字符串。即使您想坚持使用 openStream()
-on-a-URL
方法,现代 JSON 解析器(Moshi、Gson,甚至 [=29 中的 JsonReader
=] SDK) 是流式解析器,不需要您将整个原始 JSON 读入单个字符串。
原来我调用的权限对您可以请求的页面数量有限制。
per_Page 页面的计数限制为 200 个结果。但是 page_count 限制是页面 * per_Page > 1000。所以 per_page 计数是多少并不重要。如果页面 * per_Page > 1000 比它将取消调用。即使在溪流中间。
在清单中添加 android:hardwareAccelerated="false" , android:largeHeap="true" 它适用于某些情况,
<application
android:allowBackup="true"
android:hardwareAccelerated="false"
android:largeHeap="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
我收到以下 OutOfMemoryError 异常尝试翻阅来自 API
的响应Caused by: java.lang.OutOfMemoryError: Failed to allocate a 37748744 byte allocation with 25165824 free bytes and 24MB until OOM, target footprint 268261936, growth limit 268435456 at java.util.Arrays.copyOf(Arrays.java:3257) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:649) at java.lang.StringBuilder.append(StringBuilder.java:203) at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.readAll(INatCall.java:105) at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:56) at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75) at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75) at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75) at com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.doInBackground(INatCall.java:42)
有没有更有效的方法通过rest处理大量数据? 我的应用程序调用 API,returns 用户的 'entries'。 API 的最大页数是 200。大多数用户将有超过 200 个条目,这对大部分人来说都很好。我的应用程序可以分页并说明这一点。但是,有些用户将拥有 +2000 个条目,而我的应用程序 运行 内存不足,试图遍历这些较大的集合。 我的问题是:
- 有没有办法增加我的 android 应用程序的内存量 使用?
- 有哪些方法可以优化以下代码以减少使用 内存?
递归休息调用
private JSONArray restCall(URL url, JSONArray results) {
Log.d(TAG, "restCalliNat: Start");
InputStream is = null;
int totalResults = 0;
int perPage = 0;
JSONArray newResults = new JSONArray();
try {
is = url.openStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd); //<-- LINE 56
is.close();
rd.close();
JSONObject json = new JSONObject(jsonText);
newResults = json.getJSONArray("results");
totalResults = (int) json.get("total_results");
perPage = (int) json.get("per_page");
} catch (IOException | JSONException e) {
e.printStackTrace();
return null;
}
if (results != null) {
newResults = concatArray(results, newResults);
}
if (totalResults > page*perPage) {
newResults = restCall(updatePageCount(url), newResults);
}
return newResults;
}
在每个新页面上,新页面都会连接起来,直到我拥有所有条目。
private JSONArray concatArray(JSONArray arr1, JSONArray arr2) {
JSONArray result = new JSONArray();
try {
for (int i = 0; i < arr1.length(); i++) {
result.put(arr1.get(i));
}
for (int i = 0; i < arr2.length(); i++) {
result.put(arr2.get(i));
}
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
将 API 响应转换为字符串
private static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp); //<--- LINE 105
}
return sb.toString();
}
and my app is running out of memory
这与错误所说的不完全相同:Caused by: java.lang.OutOfMemoryError: Failed to allocate a 37748744 byte allocation with 25165824 free bytes and 24MB until OOM
。您有 24MB 的可用内存。但是,您正在尝试分配一个 36MB 的单个缓冲区,但这是行不通的。即使您有 124MB 或 524MB 的空闲内存,您也可能无法访问单个 36MB 的连续空闲内存块。
Converts API response to String
任一:
- 一次从您的 REST Web 服务请求更少的项目(而不是 200,尝试 5);或
- 停止尝试将整个 API 响应读入字符串,因为您的 API 响应非常大
您可能想尝试更现代的解决方案来访问 REST 样式的 Web 服务。例如,Retrofit 相当流行,不需要您将整个原始 JSON 读入单个字符串。即使您想坚持使用 openStream()
-on-a-URL
方法,现代 JSON 解析器(Moshi、Gson,甚至 [=29 中的 JsonReader
=] SDK) 是流式解析器,不需要您将整个原始 JSON 读入单个字符串。
原来我调用的权限对您可以请求的页面数量有限制。
per_Page 页面的计数限制为 200 个结果。但是 page_count 限制是页面 * per_Page > 1000。所以 per_page 计数是多少并不重要。如果页面 * per_Page > 1000 比它将取消调用。即使在溪流中间。
在清单中添加 android:hardwareAccelerated="false" , android:largeHeap="true" 它适用于某些情况,
<application
android:allowBackup="true"
android:hardwareAccelerated="false"
android:largeHeap="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">