android - 发送 PDF HTTP Post 时出现 OutOfMemoryError

标签 android http post base64 out-of-memory

我们正在为 Android 编写一个应用程序,当我们将 PDF 文件(通过 HTTP POST)发送到服务器时,应用程序崩溃并显示此异常:

09-14 15:31:59.253: D/dalvikvm(22978): GC_EXPLICIT freed 437 objects / 1236120 bytes in 47ms
09-14 15:31:59.296: D/dalvikvm(22978): GC_FOR_MALLOC freed 29 objects / 1648 bytes in 45ms
09-14 15:31:59.316: I/dalvikvm-heap(22978): Grow heap (frag case) to 13.987MB for 5171605-byte allocation
09-14 15:31:59.359: D/dalvikvm(22978): GC_FOR_MALLOC freed 0 objects / 0 bytes in 40ms
09-14 15:31:59.394: D/dalvikvm(22978): GC_FOR_MALLOC freed 2 objects / 48 bytes in 27ms
09-14 15:31:59.410: I/dalvikvm-heap(22978): Grow heap (frag case) to 20.563MB for 6895468-byte allocation
09-14 15:31:59.453: D/dalvikvm(22978): GC_FOR_MALLOC freed 0 objects / 0 bytes in 41ms
09-14 15:32:00.089: D/dalvikvm(22978): GC_FOR_MALLOC freed 5 objects / 120 bytes in 23ms
09-14 15:32:00.117: I/dalvikvm-heap(22978): Grow heap (frag case) to 33.715MB for 13790920-byte allocation
09-14 15:32:00.164: D/dalvikvm(22978): GC_FOR_MALLOC freed 0 objects / 0 bytes in 43ms
09-14 15:32:00.214: D/dalvikvm(22978): GC_FOR_MALLOC freed 13 objects / 6895864 bytes in 26ms
09-14 15:32:00.214: I/dalvikvm-heap(22978): Forcing collection of SoftReferences for 13790920-byte allocation
09-14 15:32:00.242: D/dalvikvm(22978): GC_FOR_MALLOC freed 0 objects / 0 bytes in 25ms
09-14 15:32:00.242: E/dalvikvm-heap(22978): Out of memory on a 13790920-byte allocation.
09-14 15:32:00.242: I/dalvikvm(22978): "main" prio=5 tid=1 RUNNABLE JIT
09-14 15:32:00.242: I/dalvikvm(22978):   | group="main" sCount=0 dsCount=0 s=N obj=0x4001d8b0 self=0xcd28
09-14 15:32:00.242: I/dalvikvm(22978):   | sysTid=22978 nice=0 sched=0/0 cgrp=default handle=-1345017808
09-14 15:32:00.242: I/dalvikvm(22978):   at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:~45)
09-14 15:32:00.242: I/dalvikvm(22978):   at java.nio.ReadWriteHeapByteBuffer.<init>(ReadWriteHeapByteBuffer.java:47)
09-14 15:32:00.242: I/dalvikvm(22978):   at java.nio.BufferFactory.newByteBuffer(BufferFactory.java:49)
09-14 15:32:00.242: I/dalvikvm(22978):   at java.nio.ByteBuffer.allocate(ByteBuffer.java:52)
09-14 15:32:00.242: I/dalvikvm(22978):   at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:317)
09-14 15:32:00.242: I/dalvikvm(22978):   at java.nio.charset.Charset.encode(Charset.java:692)
09-14 15:32:00.242: I/dalvikvm(22978):   at java.lang.String.getBytes(String.java:903)
09-14 15:32:00.242: I/dalvikvm(22978):   at vetic.iventory.cds.CustomEntity.getContentLength(CustomEntity.java:69)
09-14 15:32:00.242: I/dalvikvm(22978):   at org.apache.http.protocol.RequestContent.process(RequestContent.java:79)
09-14 15:32:00.242: I/dalvikvm(22978):   at org.apache.http.protocol.BasicHttpProcessor.process(BasicHttpProcessor.java:290)
09-14 15:32:00.242: I/dalvikvm(22978):   at org.apache.http.protocol.HttpRequestExecutor.preProcess(HttpRequestExecutor.java:160)
09-14 15:32:00.242: I/dalvikvm(22978):   at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:464)
09-14 15:32:00.242: I/dalvikvm(22978):   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
09-14 15:32:00.242: I/dalvikvm(22978):   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
09-14 15:32:00.242: I/dalvikvm(22978):   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
09-14 15:32:00.242: I/dalvikvm(22978):   at vetic.iventory.cds.CustomHttpClient.executeHttpCustomPost(CustomHttpClient.java:111)
09-14 15:32:00.242: I/dalvikvm(22978):   at sql.vetil.edel.EtatDesLieuxBDD.sendFile(EtatDesLieuxBDD.java:176)
09-14 15:32:00.242: I/dalvikvm(22978):   at sql.vetil.edel.EtatDesLieuxBDD.getReturnServer(EtatDesLieuxBDD.java:212)
09-14 15:32:00.242: I/dalvikvm(22978):   at vetic.iventory.cds.P8$3.onClick(P8.java:224)
09-14 15:32:00.242: I/dalvikvm(22978):   at android.view.View.performClick(View.java:2408)
09-14 15:32:00.246: I/dalvikvm(22978):   at android.view.View$PerformClick.run(View.java:8818)
09-14 15:32:00.246: I/dalvikvm(22978):   at android.os.Handler.handleCallback(Handler.java:587)
09-14 15:32:00.246: I/dalvikvm(22978):   at android.os.Handler.dispatchMessage(Handler.java:92)
09-14 15:32:00.246: I/dalvikvm(22978):   at android.os.Looper.loop(Looper.java:123)
09-14 15:32:00.246: I/dalvikvm(22978):   at android.app.ActivityThread.main(ActivityThread.java:4627)
09-14 15:32:00.246: I/dalvikvm(22978):   at java.lang.reflect.Method.invokeNative(Native Method)
09-14 15:32:00.246: I/dalvikvm(22978):   at java.lang.reflect.Method.invoke(Method.java:521)
09-14 15:32:00.246: I/dalvikvm(22978):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
09-14 15:32:00.246: I/dalvikvm(22978):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
09-14 15:32:00.246: I/dalvikvm(22978):   at dalvik.system.NativeStart.main(Native Method)
09-14 15:32:00.246: D/AndroidRuntime(22978): Shutting down VM
09-14 15:32:00.246: W/dalvikvm(22978): threadid=1: thread exiting with uncaught exception (group=0x4001d7d0)
09-14 15:32:00.253: E/AndroidRuntime(22978): FATAL EXCEPTION: main
09-14 15:32:00.253: E/AndroidRuntime(22978): java.lang.OutOfMemoryError
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:45)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.nio.ReadWriteHeapByteBuffer.<init>(ReadWriteHeapByteBuffer.java:47)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.nio.BufferFactory.newByteBuffer(BufferFactory.java:49)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.nio.ByteBuffer.allocate(ByteBuffer.java:52)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:317)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.nio.charset.Charset.encode(Charset.java:692)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.lang.String.getBytes(String.java:903)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at vetic.iventory.cds.CustomEntity.getContentLength(CustomEntity.java:69)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at org.apache.http.protocol.RequestContent.process(RequestContent.java:79)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at org.apache.http.protocol.BasicHttpProcessor.process(BasicHttpProcessor.java:290)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at org.apache.http.protocol.HttpRequestExecutor.preProcess(HttpRequestExecutor.java:160)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:464)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at vetic.iventory.cds.CustomHttpClient.executeHttpCustomPost(CustomHttpClient.java:111)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at sql.vetil.edel.EtatDesLieuxBDD.sendFile(EtatDesLieuxBDD.java:176)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at sql.vetil.edel.EtatDesLieuxBDD.getReturnServer(EtatDesLieuxBDD.java:212)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at vetic.iventory.cds.P8$3.onClick(P8.java:224)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at android.view.View.performClick(View.java:2408)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at android.view.View$PerformClick.run(View.java:8818)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at android.os.Handler.handleCallback(Handler.java:587)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at android.os.Handler.dispatchMessage(Handler.java:92)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at android.os.Looper.loop(Looper.java:123)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at android.app.ActivityThread.main(ActivityThread.java:4627)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.lang.reflect.Method.invokeNative(Native Method)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at java.lang.reflect.Method.invoke(Method.java:521)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
09-14 15:32:00.253: E/AndroidRuntime(22978):    at dalvik.system.NativeStart.main(Native Method)
09-14 15:32:19.394: I/Process(22978): Sending signal. PID: 22978 SIG: 9
09-14 15:32:19.554: D/dalvikvm(23043): GC_EXTERNAL_ALLOC freed 973 objects / 71752 bytes in 31ms
09-14 15:32:21.046: W/KeyCharacterMap(23043): No keyboard for id 0
09-14 15:32:21.046: W/KeyCharacterMap(23043): Using default keymap: /system/usr/keychars/qwerty.kcm.bin

此 fragment 中引发错误,用于计算要发送的数据的大小(这意味着文件尚未准备好发送):

try {
    size++;
    File f = new File(complexParametres.get(key)); // File to send
    InputStream is = new FileInputStream(f);
    System.gc();
    byte b[] = new byte[(int) f.length()];
    is.read(b);
    size += Base64.encodeBytes(b).getBytes().length; // Parameter encoded in Base64
    is.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

错误在这一行:

size += Base64.encodeBytes(b).getBytes().length;

你知道如何避免这个问题吗?

非常感谢。

最佳答案

check android.util.Base64OutputStream. – harism

下面的代码使用它通过任何 OutputStream 发送 Base64 编码的文件。只需调用 sendBase64Encoded(yourFile, httpPostOutputstream)

该实现使用 4kbyte 来发送任意大小的文件。

/** generic InputStream to OutputStream copy */
public static void streamCopy(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[4 * 1024];
    int read;
    while ((read = in.read(buffer)) != -1) {
        out.write(buffer, 0, read);
    }
}

/** close stuff that can be null, exceptions ignored */
public static void close(Closeable c) {
    if (c != null)
        try {
            c.close();
        } catch (IOException ignored) {
            // silence
        }
}

/** does NOT close out */
public static void sendBase64Encoded(String filename, OutputStream out) {
    File inputFile = new File(filename);
    FileInputStream source = null;
    Base64OutputStream target = null;
    try {
        source = new FileInputStream(inputFile);
        target = new Base64OutputStream(out, Base64.NO_CLOSE);
        streamCopy(source, target);
        target.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        close(source);
        close(target);
    }
}

关于android - 发送 PDF HTTP Post 时出现 OutOfMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12426010/

相关文章:

android - 带有自定义 ActionBar 的半透明 ImageSlider

android - 启用安卓 :forceDarkMode programmatically?

http - 如何发送 'hand coded' http 请求?

php - 传感器数据直播

javascript - 如何在 Node.js 中向 Post 请求添加查询

php - 发送带号码的帖子数据

c# - asp.net:如何防止用户多次发布相同的数据

android - 从 Android 应用程序写入谷歌 FireBase 不工作

java - 安装后应用程序如何打开自定义操作

javascript - 无法使用 Python 抓取网页