StringBuilder追加导致内存不足

3

我在使用循环到StringBuilder的AsyncTask中遇到了内存不足错误。 我的目标是从服务器下载图像并将其存储在SD卡中。我的代码如下:

HttpClient httpclient = new DefaultHttpClient();
        httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);   
        HttpPost httppost = new HttpPost(severPath);        

        httppost.setEntity(params[0]);
        System.out.println("executing request " + httppost.getRequestLine());



            HttpResponse response = null;
            try {
                response = httpclient.execute(httppost);
            } catch (ClientProtocolException e6) {
                // TODO Auto-generated catch block
                e6.printStackTrace();
            } catch (IOException e6) {
                // TODO Auto-generated catch block
                e6.printStackTrace();
            }
            String output;
            System.out.println("Output from Server .... \n");

            BufferedReader br = null;
            try {
                br = new BufferedReader(
                        new InputStreamReader((response.getEntity().getContent())));
            } catch (IllegalStateException e5) {
                // TODO Auto-generated catch block
                e5.printStackTrace();
            } catch (IOException e5) {
                // TODO Auto-generated catch block
                e5.printStackTrace();
            }

             OutputStreamWriter outputStreamWriter = null;
            try {
                outputStreamWriter = new OutputStreamWriter(context.openFileOutput("LargeImages.txt", context.MODE_PRIVATE));
            } catch (FileNotFoundException e6) {
                // TODO Auto-generated catch block
                e6.printStackTrace();
            }
            int i = 0;


            StringBuilder builder = new StringBuilder();


            String Result = "";
                try {
                    for (String line = null; (line = br.readLine()) != null ; ) {
                                        builder.append(line.toString());

                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }




                    outputStreamWriter.close();

我遇到了内存分配错误,请帮忙解决。我尝试了很多方法,但没有找到正确的解决方案。

循环迭代了多少次? - Gurminder Singh
你的for循环在没有更多可用行之后正确终止了吗? - Scary Wombat
你能稍微扩展一下你的代码吗? - Ashok kumar
@GurminderSingh 直到导致内存分配错误之前有相当多的东西。 - nick
@user2310289 还有代码行数,但是内存已经不足了。 - nick
显示剩余2条评论
3个回答

0
可能有两个问题。 第一个问题是循环 for (String line = null; (line = br.readLine()) != null ; ) 没有正确终止。尝试通过打开一个小文件(例如总共有10行)来找出问题所在。
第二个问题实际上是内存不足的情况。可能不是使用字符串获取图像的最佳方法,因为图像可能非常大,创建大量的字符串会导致自然的内存错误。尝试找到另一种方法。

0
如果您正在下载图像,则不应使用Reader/Writer/StringBuilder来存储其内容。因为文件是二进制内容,所以由于Reader/Writer类使用的字符编码,内容将被混淆。
尝试使用InputStream/OutputStream,直接将内容存储到SD卡中,而不将其存储在内存中。
请尝试以下代码:
InputStream in = response.getEntity().getContent();
OutputStream out = context.openFileOutput("LargeImages.txt", context.MODE_PRIVATE);
byte b[] = new byte[4096];
int i;
while ((i = in.read(b)) >= 0) {
    out.write(b, 0, i);
}

@nick,我刚刚添加了它。 - Claudiu

0

我没有看到实际写入输出流的代码。在关闭之前,不应该有一行像 outputStreamWriter.print(builder) 这样的代码吗?

关于你的问题。与其在内存中收集整个数据并一次性写入,你应该直接在 for 循环中写入每一行。你根本不需要 StringBuilder。这是一个代码片段:

            try {
                for (String line = br.readLine(); line != null; line = br.readLine()) {
                    outputStreamWriter.append(line);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return;
            }

另外三点:

  • 当你遇到异常时,应该停止操作,例如从你的方法中返回。你上面的代码会打印堆栈跟踪(这肯定是有帮助的),但然后会继续执行,这将不太有帮助。只需在每个printstackTrace之后添加return即可。
  • 仍有可能一行过长而超出内存限制,但风险已被最小化。
  • 你下载的数据是二进制图像还是文本?你称其为图像,但你下载的是文本。请注意字节和字符(使用字符集编码)之间的区别,并保持在实际接收到的范围内。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接