java - Android:在不耗尽内存的情况下将流转换为字符串

标签 java android json out-of-memory

我有一个 android 客户端,它通过 REST-ful 端点和 JSON 与服务器通信。因此,我需要在将其转换为哈希之前检索完整的服务器响应。我已经准备好执行此操作的代码(可在互联网上的某个地方找到):

private static String convertStreamToString(InputStream is) {

    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();

    String line = null;
    try {
        while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return sb.toString();
}

该代码在大部分情况下都有效,但是我看到来自客户端的现场崩溃报告,该行出现 OutOfMemory 异常:

    while ((line = reader.readLine()) != null) {

完整的堆栈跟踪是:

java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:200)
    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
    at java.lang.Thread.run(Thread.java:1102)
Caused by: java.lang.OutOfMemoryError
    at java.lang.String.(String.java:468)
    at java.lang.AbstractStringBuilder.toString(AbstractStringBuilder.java:659)
    at java.lang.StringBuilder.toString(StringBuilder.java:664)
    at java.io.BufferedReader.readLine(BufferedReader.java:448)
    at com.appspot.myapp.util.RestClient.convertStreamToString(RestClient.java:303)
    at com.appspot.myapp.util.RestClient.executeRequest(RestClient.java:281)
    at com.appspot.myapp.util.RestClient.Execute(RestClient.java:178)
    at com.appspot.myapp.$LoadProfilesTask.doInBackground(GridViewActivity.java:1178)
    at com.appspot.myapp.$LoadProfilesTask.doInBackground(GridViewActivity.java:1)
    at android.os.AsyncTask$2.call(AsyncTask.java:185)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
    ... 4 more

我的问题:除了从服务器发送较小的数据 block 之外,还有什么方法可以解决这个问题吗?

谢谢!

最佳答案

一般来说,答案是否定的,但您当然可以调整导致内存不足的条件。特别是,如果您在流之前发送字符串长度,您将能够在其中创建一个具有正确数组大小的 StringBuilder。数组在创建后无法调整大小,因此如果您用完 StringBuilder 中的数组容量,实现必须分配一个新数组(通常是大小的两倍以避免调整太多),然后复制旧数组内容。考虑大小为 X 的流,要调整恰好是 X-1 容量的 StringBuilder 的大小,您需要几乎 X*3 的内存量。调整 StringBuilder 的大小以避免调整大小将允许您将更大的流压缩到内存中。

您可能想要做的另一件事是调整服务器进程可用的内存量。启动服务器进程时使用类似 -Xmx1024m 的开关。

当然,修改您的算法以不需要将整个流保存在内存中会更好。它将使您能够使用相同数量的硬件处理更多客户端。

关于java - Android:在不耗尽内存的情况下将流转换为字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4729188/

相关文章:

mysql - 如何格式化 SQL 查询返回的数据结构

android - 最新的 Google 应用内结算版本是什么?

javascript - 如何在 Phaser 中的 mapLayer 上获取平铺类型

java - 为什么我们调用 Class.forname ("com.mysql.jdbc.Driver") 即使在类路径中添加了 mysql.jar

java - 将 base64 格式的图像发送到 Java 网络服务器,转换并保存

android - 如何在 Android 中为棉花糖制作一个电话按钮

android - 验证点是否被圈出的算法

javascript - 如何根据特定的 JSON 对象值对数组进行计数?

java - 12GB Ram 机器的 Pentaho OutOfMemory 异常

java - 为什么 print 会解除阻塞执行?