4g内存 堆内存分配多少_我需要多少内存
4g內(nèi)存 堆內(nèi)存分配多少
什么是保留堆?
我需要多少內(nèi)存? 在構(gòu)建解決方案,創(chuàng)建數(shù)據(jù)結(jié)構(gòu)或選擇算法時(shí),您可能會問自己(或其他人)這個(gè)問題。 如果此圖包含1,000,000條邊并且我使用HashMap進(jìn)行存儲,此圖是否適合我的3G堆? 構(gòu)建我的自定義緩存解決方案時(shí),我可以使用標(biāo)準(zhǔn)的Collections API還是它們帶來的開銷過多?
顯然,簡單問題的答案要復(fù)雜一些。 在這篇文章中,我們將對此做一個(gè)初步的了解,看看實(shí)際上兔子洞有多深。
標(biāo)題中問題的答案分為幾個(gè)部分。 首先,我們需要了解您是對淺堆大小還是保留堆大小感興趣。
淺堆很容易–它僅由對象本身占用的堆組成。 在計(jì)算方法上有一些細(xì)微差別,但是對于本文的范圍,我們將其保留不變。 請繼續(xù)關(guān)注同一主題的未來帖子。
保留的堆在許多方面都更加有趣。 很少有人對淺堆感興趣,在大多數(shù)情況下,您的實(shí)際問題可以轉(zhuǎn)換為“如果我從內(nèi)存中刪除此對象,那么垃圾收集器現(xiàn)在可以釋放多少內(nèi)存”。
現(xiàn)在,眾所周知,所有Java垃圾回收(GC)算法都遵循以下邏輯:
現(xiàn)在,為了說明如何計(jì)算保留的堆,讓我們通過以下示例對象遵循上述算法:
為了簡化示例,讓我們估計(jì)所有對象O1-O4的淺堆為1024B = 1kB。 讓我們開始計(jì)算這些對象的保留大小。
- O4沒有引用其他對象,因此它的保留大小等于其1kB的淺大小。
- O3引用了O4。 因此,垃圾收集O3意味著O4也有資格進(jìn)行垃圾收集,因此我們可以說O3保留的堆為 2kB 。
- O2引用了O3。 但是現(xiàn)在需要注意的是,從O2刪除指向O3的指針并不能使O3符合GC的條件,因?yàn)镺1仍然有指向它的指針。 因此, O2保留的堆只有1kB 。
- 另一方面,O1是在此小圖中保留所有引用的對象,因此,如果我們刪除O1,則該圖上的所有內(nèi)容都將被垃圾回收。 因此, O1保留的堆為4kB 。
實(shí)際上有什么影響? 實(shí)際上,了解淺堆大小和保留堆大小之間的差異使使用內(nèi)存分析器和堆轉(zhuǎn)儲分析器之類的工具成為可能–例如,如果您不知道如何區(qū)分這兩種方法,那么挖掘Eclipse MAT可能被證明是不可能的。堆大小測量的類型。
什么是淺堆?
本文是本系列的第二篇文章,我們將嘗試回答這些問題。 最后一篇文章解釋了對象的保留大小和淺大小之間的區(qū)別。 在本文中,我們還提供了一個(gè)如何計(jì)算數(shù)據(jù)結(jié)構(gòu)的保留堆大小的示例。 在今天的文章中,我們將擴(kuò)展上一篇文章中所謂的“簡單”。 即– 什么是以及如何測量對象使用的淺堆。
在第一篇文章中,我們指出計(jì)算淺堆大小很容易–從而僅由對象本身占用的堆組成,從而大大降低了復(fù)雜性。 但是,如何計(jì)算對象“自身”需要多少內(nèi)存呢? 顯然有一個(gè)公式:
Shallow Heap Size = [reference to the class definition] + space for superclass fields + space for instance fields + [alignment]
似乎不太有用,是嗎? 讓我們嘗試使用以下示例代碼來應(yīng)用公式:
class X {int a;byte b;java.lang.Integer c = new java.lang.Integer(); }class Y extends X {java.util.List d;java.util.Date e; }現(xiàn)在,我們努力回答的問題是– 一個(gè)Y實(shí)例需要多少淺堆大小? 讓我們開始計(jì)算它,假設(shè)我們使用的是32位x86體系結(jié)構(gòu):
作為起點(diǎn)– Y是X的子類,因此它的大小包括超類中的“某物”。 因此,在計(jì)算Y的大小之前,我們先考慮計(jì)算X的淺大小。
跳到X上的計(jì)算中,前8個(gè)字節(jié)用于引用其類定義。 該引用始終存在于所有Java對象中,并且被JVM用來定義以下狀態(tài)的內(nèi)存布局。 它還具有三個(gè)實(shí)例變量–一個(gè)int,一個(gè)Integer和一個(gè)字節(jié)。 這些實(shí)例變量需要堆,如下所示:
- 一個(gè)字節(jié)就是應(yīng)該的。 內(nèi)存中有1個(gè)字節(jié)。
- 我們的32位架構(gòu)中的int需要4個(gè)字節(jié)。
- 對整數(shù)的引用也需要4個(gè)字節(jié)。 請注意,在計(jì)算保留堆時(shí),我們還應(yīng)考慮包裝到Integer對象中的原語的大小,但是在此處計(jì)算淺堆時(shí),我們在計(jì)算中僅使用4個(gè)字節(jié)的參考大小。
那么-是嗎? X的淺堆=從引用到類定義的8個(gè)字節(jié)+ 1個(gè)字節(jié)(該字節(jié))+ 4個(gè)字節(jié)(int)+ 4個(gè)字節(jié)(對Integer的引用)= 17個(gè)字節(jié)? 實(shí)際上–不 。 現(xiàn)在起作用的是對齊(也稱為填充)。 這意味著JVM以8字節(jié)的倍數(shù)分配內(nèi)存,因此如果我們創(chuàng)建X的實(shí)例,我們將分配24字節(jié)而不是17字節(jié)。
如果您可以在這里關(guān)注我們,那很好,但是現(xiàn)在我們嘗試使事情變得更加復(fù)雜。 我們不是在創(chuàng)建X的實(shí)例,而是在創(chuàng)建Y的實(shí)例。這意味著–我們可以從引用中減去8個(gè)字節(jié)到類定義和對齊方式。 乍一看可能不太明顯,但是–您是否注意到,在計(jì)算X的淺小尺寸時(shí),我們沒有考慮到它也擴(kuò)展了java.lang.Object,因?yàn)樗蓄惗歼@樣做,即使您未在其中明確聲明它也是如此。您的源代碼? 我們不必考慮超類的標(biāo)頭大小,因?yàn)镴VM足夠聰明,可以從類定義本身進(jìn)行檢查,而不必一直將其復(fù)制到對象標(biāo)頭中。
對齊也是如此–創(chuàng)建對象時(shí),您只能對齊一次,而不是在超類/子類定義的邊界。 因此,可以肯定地說,當(dāng)創(chuàng)建X的子類時(shí),您只會從實(shí)例變量繼承9個(gè)字節(jié)。
最后,我們可以跳到初始任務(wù)并開始計(jì)算Y的大小。正如我們所看到的,我們已經(jīng)在超類字段中丟失了9個(gè)字節(jié)。 讓我們看看實(shí)際構(gòu)造Y的實(shí)例時(shí)會添加什么。
- Y的標(biāo)頭引用其類定義占用8個(gè)字節(jié)。 與以前的相同。
- 日期是對對象的引用。 4字節(jié)。 簡單。
- 該列表是對集合的引用。 同樣是4個(gè)字節(jié)。 不重要的。
因此,除了超類中的9個(gè)字節(jié)外,我們還有8個(gè)字節(jié)的頭空間,2×4個(gè)字節(jié)的數(shù)據(jù)來自兩個(gè)引用(列表和日期)。 Y實(shí)例的總淺層大小為25個(gè)字節(jié),對齊為32個(gè)字節(jié)。
為了使計(jì)算更易于遵循,我們將其匯總在下圖中:
| 1個(gè) | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | |
| 對齊 | 對齊 | 對齊 | 對齊 | |||||||||||||||||||||||||||||
| X | 目的 | 一個(gè) | b | C | ||||||||||||||||||||||||||||
| ? | 目的 | 一個(gè) | b | C | d | ? |
您可以用這些知識做什么? 加上計(jì)算保留堆大小的技巧(在我的最新文章中已經(jīng)介紹過 ),您現(xiàn)在擁有了計(jì)算數(shù)據(jù)結(jié)構(gòu)實(shí)際需要多少內(nèi)存的最終能力。
為了使事情變得更加有趣,我們創(chuàng)建了一個(gè)實(shí)用程序,該實(shí)用程序可以測量對象的淺堆和保留堆的大小。 在不久的將來,我們將免費(fèi)提供該工具。 訂閱我們的Twitter feed,敬請關(guān)注!
測量,不要猜測
看起來很簡單的任務(wù)實(shí)際上可能變得有些復(fù)雜。 在計(jì)算對象的內(nèi)存占用量時(shí),您需要牢記很多不同方面:
- 我是否需要測量淺堆或保留堆大小?
- 我是否要針對32位或64位架構(gòu)進(jìn)行計(jì)算?
- 我是在x86,SPARC,POWER還是其他無法想象的東西上運(yùn)行?
- 是否使用壓縮或未壓縮的普通對象指針?
- [在此處輸入您擔(dān)心或不完全理解的其他內(nèi)容]
當(dāng)試圖滿足另一個(gè)截止日期時(shí),在嘗試估計(jì)數(shù)據(jù)結(jié)構(gòu)的大小時(shí)牢記所有這些方面是完全不合理的。 因此,我們繼續(xù)將Java Champion Heinz Kabutz發(fā)布的代碼打包為Java代理,并提供了一種輕松的方法將其添加到您的應(yīng)用程序中。
添加代理為您提供了一種簡便的方法來跟蹤實(shí)際環(huán)境中數(shù)據(jù)結(jié)構(gòu)占用的內(nèi)存量。 并做到了沒有其他選擇所帶來的復(fù)雜性。 在以下四個(gè)簡單的步驟中,您正在運(yùn)行并最終了解寶貴的緩存實(shí)際消耗了多少內(nèi)存:
步驟1: 下載代理。 不用擔(dān)心,它只有幾千字節(jié)。
步驟2:解壓縮下載的代理。 您會看到它與源代碼打包在一起,并附帶了有關(guān)如何使用它的示例。 隨意使用代碼。
nikita-mb:sizeof nikita$ ls -l total 16 -rw-r--r-- 1 nikita staff 1696 Aug 28 22:12 build.xml -rw-r--r-- 1 nikita staff 3938 Aug 28 22:33 sizeofagent.jar drwxr-xr-x 5 nikita staff ?170 Aug 28 10:44 src步驟3:嘗試?yán)壍臏y試用例。 捆綁的測試用例測量的數(shù)據(jù)結(jié)構(gòu)與我們在博客文章中描述的有關(guān)淺堆大小測量的數(shù)據(jù)結(jié)構(gòu)相同。 對于那些不愿意來回點(diǎn)擊的人,這里再次是代碼:
class X {int a;byte b;java.lang.Integer c = new java.lang.Integer(); }class Y extends X {java.util.List d;java.util.Date e; }該測試用例隨Ant測試一起提供,以編譯和運(yùn)行示例。 如果您使用的是32位體系結(jié)構(gòu),請運(yùn)行ant test或ant test-32 。 使用ant test運(yùn)行所有測試時(shí),應(yīng)該看到以下輸出:
nikita-mb:sizeof nikita$ ant testBuildfile: /Users/nikita/workspace/sizeof/build.xmlinit:compile:test32:[java] java.lang.Object: shallow size=8 bytes, retained=8 bytes[java] eu.plumbr.sizeof.test.X: shallow size=24 bytes, retained=40 bytes[java] eu.plumbr.sizeof.test.Y: shallow size=32 bytes, retained=48 bytestest64+UseCompressedOops:[java] java.lang.Object: shallow size=16 bytes, retained=16 bytes[java] eu.plumbr.sizeof.test.X: shallow size=24 bytes, retained=40 bytes[java] eu.plumbr.sizeof.test.Y: shallow size=32 bytes, retained=48 bytestest64-UseCompressedOops:[java] java.lang.Object: shallow size=16 bytes, retained=16 bytes[java] eu.plumbr.sizeof.test.X: shallow size=32 bytes, retained=56 bytes[java] eu.plumbr.sizeof.test.Y: shallow size=48 bytes, retained=72 bytestest:BUILD SUCCESSFUL Total time: 2 seconds從上面的測試中,您可以看到例如在32位體系結(jié)構(gòu)上,Y的淺堆消耗32個(gè)字節(jié),而保留堆則占用48個(gè)字節(jié)。 在帶有-XX:-UseCompressedOops的64位體系結(jié)構(gòu)上,淺層大小增加到48個(gè)字節(jié),保留堆大小增加到72個(gè)字節(jié)。 如果您對我們?nèi)绾斡?jì)算這些數(shù)字感到困惑,那么請從本系列的先前文章中了解什么是以及如何計(jì)算淺層和保留堆大小。
步驟4:將代理附加到您自己的Java應(yīng)用程序。 為此,將-javaagent:path-to/sizeofagent.jar到JVM啟動腳本中。 現(xiàn)在,您可以通過在代碼中直接調(diào)用MemoryCounterAgent.deepSizeOf(yourObject)來測量淺堆消耗,或通過直接調(diào)用MemoryCounterAgent.sizeOf(yourObject)測量保留的堆消耗。 另請參閱捆綁的ant腳本和eu.plumbr.sizeof.test.SizeOfSample類,以防在執(zhí)行過程中感到困惑。
當(dāng)然,您有許多選擇,尤其是以內(nèi)存分析器和APM解決方案的形式。 但是,這個(gè)小型代理將快速完成其任務(wù),幾乎不需要設(shè)置或?qū)W習(xí)。 好吧,至少我們玩得很開心。 而不是處理我們的產(chǎn)品積壓 。
PS。 在撰寫本文時(shí),以下在線資源被用作靈感來源:
- http://memoryanalyzer.blogspot.com/2010/02/heap-dump-analysis-with-memory-analyzer.html
- http://www.javamex.com/tutorials/memory/object_memory_usage.shtml
- http://www.javamex.com/tutorials/memory/instrumentation.shtml
- http://kohlerm.blogspot.com/2008/12/how-much-memory-is-used-by-my-java.html
- http://www.javaspecialists.eu/archive/Issue142.html
而且-不要忘了將此代碼祝賀您發(fā)送給Heinz Kabutz,后者最初于2007年3月在Java專家通訊中發(fā)布了該代碼。
參考: 我需要多少內(nèi)存(第1部分)–保留的堆是什么? , 我需要多少內(nèi)存(第2部分)–什么是淺堆? , 我需要多少內(nèi)存(第3部分)–衡量一下,不要從我們的JCG合作伙伴 Nikita Salnikov Tarnovski (在Plumbr Blog博客上) 猜到 。
翻譯自: https://www.javacodegeeks.com/2012/12/how-much-memory-do-i-need.html
4g內(nèi)存 堆內(nèi)存分配多少
總結(jié)
以上是生活随笔為你收集整理的4g内存 堆内存分配多少_我需要多少内存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (linux client)
- 下一篇: 食堂备案有哪些(食堂备案)