2010-07-01 94 views
3

我有一個非常大的對象,我想序列化。在序列化過程中,它佔用大約130MB的堆作爲weblogic.utils.io.UnsyncByteArrayOutputStream。我正在使用BufferedOutputStream來加速將數據寫入磁盤,這可以減少此對象在內存中的存儲時間。在java序列化過程中可以緩存對象嗎?

雖然可以使用緩衝區來減少內存中對象的大小嗎?如果有一種方法一次將其序列化爲x個字節並將這些字節寫入磁盤將會很好。

如果有任何用途,請遵循示例代碼。儘管我不這麼認爲,但還沒有太多的事情要做。如果這種情況需要一個完整的內存中要被序列化的對象的副本(因此沒有序列化緩衝區的概念),那麼我認爲我被卡住了。

ObjectOutputStream tmpSerFileObjectStream = null; 
    OutputStream tmpSerFileStream = null; 
    BufferedOutputStream bufferedStream = null; 
    try { 

     tmpSerFileStream = new FileOutputStream(tmpSerFile); 
     bufferedStream = new BufferedOutputStream(tmpSerFileStream); 

     tmpSerFileObjectStream = new ObjectOutputStream(bufferedStream); 
     tmpSerFileObjectStream.writeObject(siteGroup); 
     tmpSerFileObjectStream.flush(); 

    } catch (InvalidClassException invalidClassEx) { 
     throw new SiteGroupRepositoryException(
       "Problem encountered with class being serialised", invalidClassEx); 
    } catch (NotSerializableException notSerializableEx) { 
     throw new SiteGroupRepositoryException(
       "Object to be serialized does not implement " + Serializable.class, 
       notSerializableEx); 
    } catch (IOException ioEx) { 
     throw new SiteGroupRepositoryException(
       "Problem encountered while writing ser file", ioEx); 
    } catch (Exception ex) { 
     throw new SiteGroupRepositoryException(
       "Unexpected exception encountered while writing ser file", ex); 
    } finally { 
     if (tmpSerFileObjectStream != null) { 
      try { 
       tmpSerFileObjectStream.close(); 
       if(null!=tmpSerFileStream)tmpSerFileStream.close(); 
       if(null!=bufferedStream)bufferedStream.close(); 
      } catch (IOException ioEx) { 
       logger.warn("Exception caught on trying to close ser file stream", ioEx); 
      } 
     } 
    } 
+0

你可以發佈你的序列化邏輯的一些示例代碼?這裏沒有東西加在一起 ​​- 這個weblogic類從哪裏來? – 2010-07-01 12:00:07

回答

0

什麼是您試圖保存的「siteGroup」對象?我問,因爲任何一個對象的大小都不可能是130MB,除非它有一個巨大的列表/數組/地圖/其中的任何內容 - 如果是這樣的話,答案就是將這些數據保存在數據庫中。

但是,如果對象中沒有怪物集合,那麼問題可能是對象樹包含對bagillion對象的引用,並且序列化當然會進行深層複製(這一事實已被用作實現快捷方式克隆()很多次),所以所有東西都以自上而下的方式一次全部編入目錄。

如果這是問題,那麼解決方案將實現自己的序列化方案,其中每個對象以自底向上的方式被序列化,可能在多個文件中,並且只有引用被維護到其他對象,而不是整個事情。這將允許您單獨編寫每個對象,這會產生您正在尋找的效果:由於將數據寫入塊中所導致的更小的內存佔用量。

但是,實現自己的序列化,比如實現clone()方法並不是那麼容易。所以這是一個成本/收益的事情。

+0

它確實包含確實存在於數據庫中的對象的巨大映射。序列化僅用於啓動的速度,因爲從數據庫構建映射需要花費幾個小時,而不是從磁盤花費不到一分鐘。 – 2010-09-24 13:09:23

+0

啊。這實際上可以讓事情變得更簡單......你可以瀏覽地圖並單獨序列化所有這些對象,然後清除地圖並序列化主siteGroup對象?在啓動時,你可以逆轉這個過程:構建地圖,然後將其放入對象中。這可能會使最大堆大小下降很多。 – 2010-09-28 02:37:51

0

爲什麼它佔用所有這些字節作爲UNSYNC字節數組輸出流?

這不是默認序列化的工作方式。你必須有一些特殊的代碼才能做到這一點。解決方案:不要。

+0

weblogic.utils.io.UnsyncByteArrayOutputStream在堆轉儲中可見,這是我從中獲取信息的地方。這個例程導致間歇性的內存不足錯誤,因此是個問題。對於Weblogic如何選擇處理序列化,我不認爲我能做些什麼。 – 2010-07-01 10:45:24

+0

@MarkChorley問題中沒有堆轉儲。如果您遺漏了重要信息,請勿。 – EJP 2017-01-05 09:38:49

0

這聽起來像你正在使用的任何運行時都有一個不太理想的對象序列化實現,你可能沒有任何控制權。

這裏提到了一個類似的投訴,雖然它已經很老了。 http://objectmix.com/weblogic/523772-outofmemoryerror-adapter.html

你能用更新版本的weblogic嗎?你能在單元測試中重現嗎?如果是這樣,請嘗試在不同的JVM下運行它,看看會發生什麼。

+0

Weblogic 9.2.3,使用較新的版本不幸在短期內不可行。 JDK 1.5.0.16以及如果有幫助。 – 2010-09-23 13:41:32

+1

這個Java錯誤解釋了對象序列化如何在封面下工作。它提供了一個解釋爲什麼整個對象必須保存在緩衝區中。對於你的情況,你將不得不把你的大對象分成更小的對象,並調用ObjectOutputStream上的reset()來幫助分解它。 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4363937 – wolfcastle 2010-09-23 16:45:03

0

我不知道有關WebLogic(那就是 - JRockit的我覺得)特別系列化:老實說,我看不出有任何理由使用ByteArrayOutputStreams ...

您可能要實現java.io.Externalizable如果你需要更多的控制如何將對象序列化 - 或者如果您不想自己編寫讀/寫方法(如果有許多大類),則切換到完全不同的序列化系統(例如:Terracotta)。

2

這在許多層面上都是錯誤的。這是一個大規模的序列化濫用。序列化主要用於臨時存儲對象。例如,

  1. 會話對象之間的tomcat服務器重新啓動。 JVM之間
  2. 傳輸對象(在網站負載均衡)

Java的序列沒有努力處理對象的長期存儲(無版本支持),不得處理大型物體良好。

對於一些這麼大,我先提出一些調查:

  1. 確保你是不是想堅持整個JVM堆。
  2. 查找可以標記爲'transient'的成員變量,以避免將它們包含在序列化中(可能引用了服務對象)
  3. 考慮存在內存泄漏並且對象過大的可能性。

如果一切確實正確,您將不得不研究java.io.Serialization的替代方案。通過java.io.Externalization進行更多控制可能會奏效。但我會建議像json或xml表示。

更新:

調查:

  1. google's protocol buffer
  2. facebook's Thrift
  3. Avro
  4. Cisco's Etch

Take a look at this benchmarkings as well.

+0

所有這三點都已被考慮並取消。減少內存中對象的大小並不簡單 - 它包含類似於從CMS緩存的500,000個內容項目,並且每個內容都存儲了最少的數據。正如你推斷的那樣,它堅持磁盤來加速應用程序的重新啓動。我喜歡替代表示的聲音,因爲這會減少磁盤的大小。但是它會對序列化期間佔用的內存有什麼影響嗎? – 2010-09-23 13:37:36

+1

交叉重啓加速的問題在於,假設您只是重新啓動服務器,因爲有新版本的代碼。新版本意味着序列化的舊版本不能可靠地反序列化。所以沒有什麼可以獲得的。 – Pat 2010-09-24 05:21:24

相關問題