2013-03-06 67 views
2

我想一次向PHP服务器发送多个Json字符串[每个1 MB]。当我试图发送10条记录时,它的工作正常。但是,如果它超过了20条记录,则表示OutOfMemoryException。我看到,Android内存大小限制t0 15MB - 16MB。但没有任何线索如何解决这个问题,我正在使用下面的代码一次发送多个记录。尝试向Android中的服务器发送大型json数据时发生OutOfMemoryException?

/** Upload Data*/ 
private void submitUploadData(String url, Map<String, String> param) 
     throws IOException { 
    URL siteUrl; 
    try { 
     siteUrl = new URL(url); 
     HttpURLConnection conn = (HttpURLConnection) siteUrl 
       .openConnection(); 
     conn.setRequestMethod("POST"); 
     conn.setDoOutput(true); 
     conn.setDoInput(true); 

     DataOutputStream out = new DataOutputStream(conn.getOutputStream()); 
     String content1 = ""; 

     Set getkey = param.keySet(); 
     Iterator keyIter = getkey.iterator(); 
     String content = ""; 
     for (int i = 0; keyIter.hasNext(); i++) { 
      Object key = keyIter.next(); 
      if (i != 0) { 
       content += "&"; //Crashing here 
      } 
      content += key + "=" + param.get(key); //Crashing here 
      System.out.println("Content" + content); 
     } 

     System.out.println(content); 
     out.writeBytes(content.trim()); 
     out.flush(); 
     out.close(); 

     BufferedReader in = new BufferedReader(new InputStreamReader(
       conn.getInputStream())); 
     String jsonresponse = ""; 
     while ((jsonresponse = in.readLine()) != null) { 
      System.out.println(jsonresponse); 
      if(!jsonresponse.equals("Authorisation Successful")){ 
      updateUploadRecords(jsonresponse);} 

     } 
     in.close(); 

    } catch (MalformedURLException e) { 
     e.printStackTrace(); 
    } 
} 
+0

这可能是因为你的数据集太大了。一些快速评论 - 1)您似乎正在创建一个查询字符串,请记住,大多数代理将限制查询字符串的长度。 2)你正在用可能最糟糕的方式构建你的'内容'字符串。 – Perception 2013-03-06 09:46:31

+0

使用一个stringbuilder来构建你的内容(或者keyvalue对,或者textutils.join ...) – njzk2 2013-03-06 09:47:41

+0

@perception什么才是构建内容的正确方式? – GoCrazy 2013-03-06 09:52:59

回答

4

乍一看你的代码没有问题,但是你正在使用所有可能被称为内存浪费的方法,并且现在你正在尝试大内存不足的操作,这是保证发生。

提示:

  • 不contatenate字符串与str1 += str2 + "other val"刚刚创建存储3个新的字符串。改用StringBuilder。
  • 调用System.gc()(因为某些人会建议你)不会对你有所帮助,因为你在循环中执行此操作,该方法仅暗示系统可能是GC的好时机,但直到该系统实际上已经做到了,你已经崩溃了。
  • 如果每个JSON字符串大约为1mb,并且您传递了其中的20个,那么您已经在那些20mb的旧设备上崩溃了。你将不得不重新设计一些东西,但我的建议是只删除地图,彻底删除它。

相反,您应该(在创建该映射的方法上)使用某种类型的OutputStream来编写已经格式化为临时文件的所有数据。然后,上传你会使用某种类型的InputStream从这个文件读取和写入您的DataOutputStream

替代流是使用一些其它类的相同方法流基地,它们分别是:JsonWriter/JsonReader,但是如果它不是特定的Json,那么你也拥有FileWriter/FileReader,并且不要忘记总是用BufferedReader和BufferedWriter包装它们。

+0

嗨Budius,感谢您的提示与详细的答案。此应用仅适用于平板电脑,因此旧设备没有问题。我将用StringBuilder替换字符串。 – GoCrazy 2013-03-06 10:20:49

+0

这不是新/旧设备的问题。这是一个代码的问题,它将始终与仅在非常简单的条件下工作的代码相互作用。当你传递60或80个字符串而不是20个时,即使你的Nexus 10也会崩溃! – Budius 2013-03-06 10:26:21

+0

是的,你是对的,我必须按照你的建议去'JSONWriter' +1 – GoCrazy 2013-03-06 10:28:07

0

也许它受限于您的虚拟设备的内存大小!?

你试过了吗?给它一个更大的记忆!

+0

感谢您的回答。如何增加? – GoCrazy 2013-03-06 09:42:38

+0

你使用什么IDE?我只能告诉你日食。在那里你可以使用AVD管理器,你可以在Window-> Android虚拟设备管理器中找到...那里你可以创建一个虚拟设备,具有RAM,VM堆,内部存储等自定义值... – 2013-03-06 09:43:54

+0

我使用的是eclipse 。所以没问题,我认为 – GoCrazy 2013-03-06 09:47:26

0

您正在遍历对象。你有风险,他们保持副本等...... 回到基本和尝试使用函数String.split('');,然后用正常循环遍历它。 然后你知道哪些对象在内存中。在进行拆分时,您会得到两个内存占用对象,即原始字符串和由拆分生成的数组。

在你已经分手,你可以设置原始字符串null腾出垃圾收集器内存中的原始字符串的那一刻(甚至调用System.gc()

然后,只需简单地通过串做操作回路操控,尽可能减小占地面积。

2

通过个人经验,我发现超过一定的大小(这取决于设备),使用字符串连接来形成/下载实体是不可行的。

在你的情况下使用JsonWriter将有所帮助。它将json标记写入流中,不会占用额外的内存。当你下载庞大的json文档时,请使用JsonReader

我用这两个类都成功了。

相关问题