在尝试将大型json数据发送到android中的服务器时出现OutOfMemoryException?

我试图一次发送多个Json字符串[每个1 MB]到PHP Server。 当我试图发送10条记录时,其工作正常。 但如果超过20条记录则会显示OutOfMemoryException 。 我看到android内存大小限制为t0 15MB – 16MB。 但是没有任何线索如何解决这个问题,我使用下面的代码一次发送多条记录。

  /** Upload Data*/ private void submitUploadData(String url, Map 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(); } } 

乍一看,你的代码没有任何问题,但你正在使用所有可能的类型的方法,这种方法已知是一个内存浪费,现在你正在尝试大量内存耗尽的操作,这是有保证会发生的。

提示:

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

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

Streams的替代方法是使用一些基于与流相同的方法的其他类,它们是:JsonWriter / JsonReader,但是如果它不是特定的Json,你也有FileWriter / FileReader,你不会忘记始终用BufferedReader和BufferedWriter包装它们。

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

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

我已经成功地使用了这两个类。

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

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

你正在用对象迭代它。 你有风险,他们保留副本等…回到基础并尝试使用函数String.split(''); 然后用普通循环迭代它。 然后你知道哪些对象在内存中。 在进行拆分时,您将获得两个内存占用对象,原始字符串和拆分产生的数组。

在您拆分原始字符串的那一刻,您可以将原始字符串设置为null以释放垃圾收集器的内存(甚至可以调用System.gc()

然后只需简单地循环通过操作进行操作的字符串,保持足迹尽可能小。