2012-12-31 125 views
5

我在寫一些需要在內存中保存大量數據的「大數據」軟件。我用C++編寫了一個很好的原型。然而,實際的最終用戶通常使用Java編碼,因此他們要求我也編寫一個Java原型。java內存大小優化

我已經完成了對java內存佔用和一些初步測試的背景閱讀。例如,假設我有這個對象

public class DataPoint{ 

    int cents, time, product_id, store_id; 

    public DataPoint(int cents, int time, int product_id, int store_id){ 
    this.cents = cents; 
    this.time = time; 
    this.product_id = product_id; 
    this.store_id = store_id; 
    } 
} 

在C++中,這個結構的大小是16字節,這是有道理的。在Java中,我們必須是間接的。如果我創建了這些對象(例如,10米),並在 之前使用Runtime.totalMemory() - Runtime.freeMemory(),然後根據需要進行劃分,則每個結構將獲得大約36個字節。一個~2.4倍的內存差異是非常討厭的;當我們試圖在內存中保存數以億計的數據點時,它會變得很難看。

我在某處讀到,在Java這種情況下,它更好地將數據存儲爲數組 - 實質上是基於列的存儲而不是基於行的存儲。我想我明白這一點:基於列的方式減少了引用的數量,並且JVM甚至可以智能地將這些字符串打包成8字節的字。

還有什麼其他的技巧可以用來減少本質上是一個非常大的維度(數百萬/數十億個數據點)和一個非常小的維度(O(1)列數量的內存塊的內存佔用/變量)?

結果將數據存儲爲每個條目恰好使用16個字節的4個int數組。教訓:小的對象在java中具有討厭的比例開銷。

+3

totalMemory還包含空閒內存,請嘗試使用totalMemory()來測量 - freeMemory() – Henry

+0

如果您想要一個非常準確的數字,請使用應用程序的堆轉儲並使用Memory Analyzer(http ://www.eclipse.org/mat/)以獲得準確的數字。 2nd - 這個數據的訪問模式是什麼?也許你可以通過使用一些可以將未使用的部分分頁到磁盤的緩存庫來獲得更多的空間?說你的點分成10K項目的數組,並將這些「塊」存儲在infinispan(http://www.jboss.org/infinispan/)或類似的? – radai

+0

@亨利好點!使用totalMemory()進行測量 - freeMemory()爲每個結構提供36個字節的值。優於52,但仍是C++的2倍。 – andyInCambridge

回答

2

這並不是那麼直截了當,看看你的數據結構在Java中佔用了多少內存。 totalMemory()顯示分配給vm的空間大於實際使用量。您可以嘗試使用Java Profiler來顯示數據結構的空間消耗,它們很容易設置和運行。一個便利的免費工具是Java自己的VisualVM,例如顯示應用程序的內存行爲,如果您使用它,您還將瞭解到Java的GC如何工作。

VisualVM的截圖顯示性能軌跡(從http://visualvm.java.net/features.html圖像): enter image description here

你也應該考慮做最後的變量,如果有可能。它允許Java VM更好地優化代碼位(不知道它是否節省了空間)。

+0

讓他們最終成爲一個好主意。只是測試過它,不會改變內存佔用。 – andyInCambridge

0

首先在Java所有對象的永遠是從1995年起的對象C++版本稍大封裝,使你做instanceof等是不可能在C++運行時類型信息。此外,它有助於在內存管理中手動完成自己的工作,因此您還可以將代碼的這部分視爲代碼庫的一部分。

您可以查看Flyweight Pattern以減少內存需求,以便重複使用DataPoints(使類Immutable)。我假設,如果你有幾十億分,如你所說,有些可能是相同的價值觀。
我相信這裏的其他人會給出一些關於優化內存空間的更多具體信息

0

根據值範圍,您可以使用較小的數據類型。你可以避開使用字節或簡短的一些成員?