当前位置: 首页 > 面试题库 >

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

南门棋
2023-03-14
问题内容

我有一个android客户端,可通过REST风格的端点和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

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

谢谢!


问题答案:

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

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

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



 类似资料:
  • 问题内容: 我有一个字符串,是这样的:。 我想将其转换为列表。我知道我可以使用eval(string)来获取列表,但是eval令我感到恐惧,因为它可能会造成灾难(并且因为我可以获取非列表作为有效输出)。还有另一种更安全的方式将此字符串转换为列表吗?我知道这是一个列表,所有不是列表的数据都是无效数据(应该检查和/或抛出错误)。 问题答案: 如果您坚持要这样做,可以使用ast.literal_eval

  • 问题内容: 我需要一个解决方案将String转换为字节数组,而无需像这样更改: 输入: 输出: 当我使用 那么回复是 但我希望回复是 问题答案: 您应始终确保序列化和反序列化使用相同的字符集,这会将字符映射到字节序列,反之亦然。默认情况下,String.getBytes()和新的String(bytes)使用默认字符集,该字符集可能是特定于语言环境的。 使用getBytes(Charset)重载

  • 我的任务是创建一个方法,该方法将接受用户输入的3位数int,并输出其反方向(123-321)。我不允许将int转换为字符串,否则我将失去分数,我也不允许打印main以外的任何地方。

  • 我有以下代码: 当我用java 8运行代码时,它可以工作。但对于java 11,它抛出了一个例外:java。时间总体安排DateTimeParseException:无法在索引3处分析文本“20 Janeiro 2021 00:26”。 我也有类似的情况,我要转换的字符串中有一个区域,代码是: 如果使用java 8运行,它仍然有效,但使用java 11则不行。异常是:java.time.forma

  • 问题内容: 每次更新同一张图片时,图像质量都会通过图像压缩方法降低。 我不想一次又一次地压缩图像。请提出一些建议。 问题答案: 首先,使用PNG压缩不会丢失图像质量。 如果仍要获取不压缩的字节,则可以尝试以下操作: 要从字节数组取回:

  • 问题内容: 每次更新同一张图片时,图像质量都会通过图像压缩方法降低。 我不想一次又一次地压缩图像。请提出一些建议。 问题答案: 首先,使用PNG压缩不会丢失图像质量。 如果仍要获取不压缩的字节,则可以尝试以下操作: 要从字节数组取回: