简体   繁体   中英

StringBuilder append cause out of memory

i am getting out of memory error in asynctask which loop to stringbuilder . My target for using this to download image from server and store inside my sd card.My code as below :

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();

i am getting out of memory allocation error. please help. i try many method but also not getting the right.

There may be two problems. The first - the cycle for (String line = null; (line = br.readLine()) != null ; ) is not terminated properly. Try to find it out by opening a small file(eg with 10 lines total).

The second - it's actually a memory insufficient case. Probably it's not the best idea to get image via strings as images may be very heavy and creating a plenty of Strings causes natural memory error. Try to find another approach.

if you are downloading an image, then you should not use Reader/Writer/StringBuilder to store it's content. Because the file is binary content will be scrambled because of the character encoding used by Reader/Writer classes.

Try using InputStream/OutputStream and store the content directly to sdcard without storing it in memory.

Try out the below code:

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);
}

I don't see code that is actually writing to the output stream. Shouldn't there be a line before the close, that is like outputStreamWriter.print(builder) ?

About your question. Instead of collecting the whole data in memory in a StringBuilder and than write it at once, you should write directly each line you get within your for-loop. You don't need the StringBuilder at all. Here's a code snippet:

            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;
            }

Three more remarks:

  • When you get an Exception you should also stop the action, eg return from your method. Your code above would print the Stacktrace (which is definitely helpful) but would then continue, which would be not so helpful. Just add return after each printstackTrace .
  • There's still a chance that one line is too long for memory, but the risk is minimized.
  • Is the data you download binary image or text? You name it image but you download text. Please be aware that there's a difference between bytes and characters (encoded with character set) and stay within what you actually receive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM