OutOfMemoryError:分页响应时分配失败
Posted
技术标签:
【中文标题】OutOfMemoryError:分页响应时分配失败【英文标题】:OutOfMemoryError: Failed to allocate when paging through responses 【发布时间】:2021-12-24 09:18:48 【问题描述】:我收到以下 OutOfMemoryError 异常尝试通过 API 的响应分页
原因:java.lang.OutOfMemoryError:无法分配 37748744 字节分配,25165824 空闲字节和 24MB 直到 OOM,目标占用空间 268261936,增长限制 268435456 在 java.util.Arrays.copyOf(Arrays.java:3257) 在 java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124) 在 java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:649) 在 java.lang.StringBuilder.append(StringBuilder.java:203) 在 com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.readAll(INatCall.java:105) 在 com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:56) 在 com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75) 在 com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75) 在 com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.restCalliNat(INatCall.java:75) 在 com.richmondgamesstudio.inattaxonomytreeviewer.utils.INatCall.doInBackground(INatCall.java:42)
有没有更有效的方法通过休息来处理大量数据? 我的应用程序调用返回用户“条目”的 API。 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();
【问题讨论】:
【参考方案1】:在你的清单中添加 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">
【讨论】:
【参考方案2】:原来我所调用的权限对您可以请求的页面数量有限制。
每页计数限制为 200 个页面结果。但是 page_count 限制是 page * per_Page > 1000。所以 per_page 计数是多少并不重要。如果 page * per_Page > 1000 则将取消调用。即使在溪流中间。
【讨论】:
【参考方案3】:我的应用程序内存不足
这并不是错误所说的: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 的连续可用内存块。
将 API 响应转换为字符串
要么:
一次从您的 REST Web 服务请求更少的项目(而不是 200 个,尝试 5 个);或 停止尝试将整个 API 响应读入字符串,因为您的 API 响应非常大您可能想尝试更现代的解决方案来访问 REST 样式的 Web 服务。例如,Retrofit 非常流行,并且不需要您将整个原始 JSON 读入单个字符串。即使您想坚持使用 openStream()
-on-a-URL
方法,现代 JSON 解析器(Moshi、Gson,甚至 Android SDK 中的 JsonReader
)都是流式解析器,不需要您阅读将整个原始 JSON 转换为单个字符串。
【讨论】:
以上是关于OutOfMemoryError:分页响应时分配失败的主要内容,如果未能解决你的问题,请参考以下文章
采用JQuery实现的打印HTML表格自动按多少行分页,打印时分页
eclipse 运行报java.lang.OutOfMemoryError: PermGen space解决方法
React Apollo Client:点击按钮时分页和获取数据
在 flexdashboard 中添加下载处理程序时分页被切断
java.lang.OutOfMemoryError: unable to create new native thread