2013-03-06 124 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

我用這兩個類都成功了。

相關問題