應(yīng)該使用32位還是64位的JVM?
應(yīng)用使用32位的JVM,還是應(yīng)該使用64位的JVM,我自己以前還真沒想過,大家都想過了嗎?本文是Plumbr中的一篇博文,為大家提了個醒。(2012.11.27最后更新)在我的企業(yè)級軟件開發(fā)職業(yè)生涯中,我多次面對這個問題。每隔一段時間我不得不建議配置一個新的特定環(huán)境。而往往該問題部分與"我應(yīng)該使用32位還是64位JVM?"這一問題有關(guān)。老實說,一開始我是靠擲硬幣來解決的,而不是給出一個合理的答案。(抱歉,兄弟們!)但現(xiàn)在我對這個問題有了更多的領(lǐng)悟,并想與你們分享。
第一步--越多越好,對嗎?即如此,因為64>32,所以答案很簡單:如果可能的話,應(yīng)該總是選擇64位?好吧,請耐心點兒。64位架構(gòu)的壞處是,相同的數(shù)據(jù)結(jié)構(gòu)會消耗更多的內(nèi)存,甚至是多很多。我們的測評顯示,根據(jù)不同的JVM版本和操作系統(tǒng)版本,以及相應(yīng)的硬件架構(gòu),最終會用掉比32位架構(gòu)多30-50%的堆內(nèi)存。更大的堆也會造成更長的GC暫停,這會對應(yīng)用程序造成潛在的影響--在4.5G的堆上執(zhí)行完全GC肯定會比在3G的堆上執(zhí)行花費更長的時間。所以,僅僅是因為64比32大就去趕64位JVM的時髦,肯定是錯誤的。
但,什么時候才是使用64位JVM的好時機呢?多數(shù)情況下,要看堆的大小。在不同的平臺下,你很快就得面對32位JVM堆內(nèi)存的上限問題。下表列出了在不同平臺下的這種限制:
Linux 2GB 特定內(nèi)核,如hugemem,可以達到3G
Windows 1.5GB 使用"/3G"的啟動參數(shù)并使用/LARGEADDRESSAWARE參數(shù)去編譯JRE,則可提高到3G
Mac OS X 3.8GB 警告--未能找到老的Mac,所以沒有對其進行測試
那么,這有什么壞處?我打賭,你肯定見過在16G的RAM上運行32位的機器。問題就在于,在只有16G RAM的Windows系統(tǒng)中,JVM只能分配到少于10%的內(nèi)存。
主因--地址空間。在32位系統(tǒng)中,理論上可以為每個進程分配4G內(nèi)存。而Windows系統(tǒng)對地址空間的處理使這一理論值無法達到。Windows將進程的地址空間砍掉了一半。一半留給了內(nèi)核(用戶進程無法使用它),另一半則留給了用戶。無論系統(tǒng)中有多大的RAM,32位進程只能使用到2G的RAM。更糟的是--地址空間必須是連續(xù)的,所以在實踐中,Windows系統(tǒng)最多只為你剩下了1.5-1.8G的堆內(nèi)存。
有一個在32位Windows系統(tǒng)中減少內(nèi)核空間并增加用戶空間的竅門,即,可以在boot.ini系統(tǒng)使用/3GB參數(shù)。然而,為了能確保它有效,必須使用/LARGEADDRESSAWARE開關(guān)去編譯或鏈接JVM。
不幸地是,至少對于HotSpot JVM無法做到這一點。直到最新的JDK 1.7版本,HotSpot JVM仍未使用該選項進行編譯。但又幸運地是,如果你運行2006年之后的JRockit版本,就能享用到2.8-2.9G的堆大小。
那么,我們是否可以得出結(jié)論,如果你的應(yīng)用要求大于2-3G的內(nèi)存,你就總是應(yīng)該運行64位的JVM?也許。但你也必須要清楚應(yīng)用的場景。我們已經(jīng)介紹了使用64位JVM的壞處--增加的堆消耗,以及更長的GC中斷。讓我們分析一下原因。
問題1:64位JVM需要多出30-50%的內(nèi)存。為什么會如此呢?主要是因為內(nèi)存是以64位架構(gòu)進行部局。首先,在64位JVM中,對象頭有12字節(jié)。其次,對象引用會占用4字節(jié)或8字節(jié),實際值取決于JVM的參數(shù)與堆的大小。相較于32位JVM的8字節(jié)對象頭和4字節(jié)對象引用,毫無疑問會增加一些開銷。在我們之前發(fā)布的博客中你會找到更多關(guān)于如何計算對象內(nèi)存的相關(guān)信息。
問題2:更長的垃圾收集中斷。構(gòu)建更大的堆意味著GC要做更多的工作去清理無用的對象。這意味著,在實際應(yīng)用中構(gòu)建大于12-16G的堆時,你必須要特別小心。沒有很好的性能調(diào)優(yōu)與測評,你很容易就會引起一個耗時數(shù)分鐘的完全GC。在應(yīng)用程序的非關(guān)鍵潛在危險場景中,通過對吞吐量的優(yōu)化或許能解決這一問題,但在多數(shù)情況下,它會造成程序中斷。
當我需要更大的內(nèi)存且又不希望引入由64位架構(gòu)所造成的開銷,那該怎么辦呢?在我們以前的一篇博文中已經(jīng)涉及了這個問題--通過對堆的分區(qū),GC調(diào)優(yōu),構(gòu)建不同的JVM,或?qū)Χ逊峙洳煌膬?nèi)存,就可以避免這一問題。
最后,讓我們重申,你應(yīng)該總是要意識到選擇64位JVM的后果,但也不要懼怕這一選擇。