【问题标题】:Upload file in Android with outofmemory error在 Android 中上传文件时出现内存不足错误
【发布时间】:2012-03-12 01:50:51
【问题描述】:

我的上传代码如下:

String end = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
try {
URL url = new URL(ActionUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestMethod("POST");
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Accept", "text/*");
con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
DataOutputStream ds = new DataOutputStream(con.getOutputStream());
ds.writeBytes(twoHyphens + boundary + end);
ds.writeBytes("Content-Disposition: form-data;" + "name=\"folder\"" + end + end);
ds.write(SavePath.getBytes("UTF-8"));
ds.writeBytes(end);
ds.writeBytes(twoHyphens + boundary + end);
ds.writeBytes("Content-Disposition: form-data;" + "name=\"Filedata\"; filename=\"");
ds.write(FileName.getBytes("UTF-8"));
ds.writeBytes("\"" + end);
ds.writeBytes(end);
FileInputStream fStream = new FileInputStream(uploadFilepath+""+FileName);
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int length = -1;
int pro = 0;
while((length = fStream.read(buffer)) != -1) {
ds.write(buffer, 0, length);
}       
ds.writeBytes(end);
ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
fStream.close();
ds.flush();
InputStream is = con.getInputStream();
int ch;
StringBuffer b = new StringBuffer();
while((ch = is.read()) != -1) {
b.append((char)ch);
}
ds.close();
}
catch(Exception e) {
e.printStackTrace();
}

它可以在上传较小的文件时工作。 但是,当更多 16 mb 时,它会上传失败并显示 OutOfMemory 错误。 我认为这是因为将所有数据都放在缓冲区中。 所以我想让它在缓冲区保存 1024 个字节的同时发送数据。 但我不知道这样做。 有人可以帮我做吗?

【问题讨论】:

  • 您可以尝试添加 ds.flush();进入 while((length = fStream.read(buffer)) != -1) { ds.write(buffer, 0, length);以便它可以将所有数据刷新到服务器...(我假设服务器将等待直到 ds.writeBytes(twoHyphens + boundary + twoHyphens + end); 调用)
  • 我试过了。它仍然在同一行出现相同的错误。

标签: android upload out-of-memory


【解决方案1】:

布莱恩,你应该添加

con.setChunkedStreamingMode(0);

之前

DataOutputStream ds = new DataOutputStream(con.getOutputStream());

如果你的服务器可以支持分块模式,或者添加

con.setFixedLengthStreamingMode(packet_size);

packet_size = upload_file_size + header_size.

【讨论】:

    【解决方案2】:

    您应该确认错误发生的时间点。我怀疑是在阅读回复期间。在这种情况下,服务器似乎会响应您在StringBuffer 中放置的大量数据。你真的需要消耗整个响应并将其保存在内存中吗?如果是文件,请保存而不是保存在内存中。


    我做了更多研究,这是另一种可能性。默认情况下,Android JVM 具有 16mb 的最大堆。有关详细信息,请参阅this

    另一方面,如果您的服务器实际上并未使用数据,则大部分数据将驻留在客户端上。因此,如果您的数据堆超过最大堆,则客户端将失败。

    所以我怀疑您的服务器只是没有从流中读取数据。

    以下类(它是代码相关部分的 sn-p)说明了这个问题。在任何 JVM 上运行它,如下所示:

    java -Xmx16m -cp . Test
    

    它会很快产生OOM。事实上,比预期的要早得多。

    import java.io.*;
    import java.net.*;
    
    public class Test {
      public static void main(String argv[]) throws Exception {
        new Thread() {
          public void run() {
            try {
               new ServerSocket(12000).accept();
            } catch (Throwable t) {
              t.printStackTrace();
            } 
          }
        }.start();
    
        URL url = new URL("http://localhost:12000/");
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);
        DataOutputStream ds = new DataOutputStream(con.getOutputStream());
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
        for (int i=0;i<100000;i++) {
          ds.write(buffer, 0, 1024);
          System.out.println("Written chunk " + i);
        }       
        ds.flush();
      }
    }
    

    【讨论】:

    • 发生在 ds.write(buffer, 0, length);在while循环中。
    • 在那部分中,除了 1024 字节缓冲区之外,您不会在内存中保留任何内容。可能与DataOutputSteram 有关,我会尝试直接写信给OutputStream,看看会发生什么。
    • 我也尝试使用 con.setFixedLengthStreamingMode(1024);。显示错误“java.io.IOException: expected 865 bytes but received 1024”。
    • 经过我的测试。行 ds.write(buffer, 0, length);在 while 循环中,我的服务器不会从流中读取。修改最大堆可以访问更大的文件(可能几个gb),然后它仍然内存不足。那我还有什么方法可以解决吗?
    • 可以告诉我如何使用 java -Xmx16m -cp 。在 Android 中测试?
    猜你喜欢
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多