我需要多少內存

什么是保留堆?

我需要多少內存? 在構建解決方案,創建數據結構或選擇算法時,您可能會問自己(或其他人)這個問題。 如果此圖包含1,000,000條邊并且我使用HashMap進行存儲,此圖是否適合我的3G堆? 我可以在構建自定義緩存解決方案時使用標準的Collections API ,還是它們造成的開銷過多?

顯然,簡單問題的答案要復雜一些。 在這篇文章中,我們將對此做一個初步的了解,看看實際上兔子洞有多深。

標題中問題的答案分為幾個部分。 首先,我們需要了解您是對淺堆大小還是保留堆大小感興趣。

淺堆很容易–它僅由對象本身占用的堆組成。 如何計算它有些細微差別,但對于本文的范圍,我們將其保留不變。 請繼續關注有關同一主題的未來帖子。

保留的堆在許多方面都更加有趣。 很少有人對淺堆感興趣,在大多數情況下,您的實際問題可以轉換為“如果我從內存中刪除該對象,那么垃圾收集器現在可以釋放多少內存”。

現在,我們都記得,所有Java垃圾回收(GC)算法都遵循以下邏輯:

  1. GC將某些對象視為“重要”對象。 這些被稱為GC根,并且(幾乎)從不丟棄。 例如,它們是當前正在執行的方法的局部變量和輸入參數,應用程序線程,來自本機代碼的引用以及類似的“全局”對象。
  2. 從那些GC根目錄引用的任何對象都被假定為正在使用,因此未被GC丟棄。 一個對象可以用Java中的不同方式引用另一個對象,在最常見的情況下,對象A存儲在對象B的字段中。在這種情況下,我們說“ B引用A”。
  3. 重復該過程,直到訪問了可以從GC根過渡獲取的所有對象并將其標記為“使用中”為止。
  4. 其他所有東西都沒有使用,可以扔掉。

現在說明如何計算保留的堆,讓我們通過以下示例對象遵循上述算法:

為了簡化示例,讓我們估計所有對象O1-O4的淺堆都為1024B = 1kB。 讓我們開始計算這些對象的保留大小。

  • O4沒有對其他對象的引用,因此其保留大小等于其1kB的淺大小。
  • O3引用了O4。 因此,垃圾收集O3意味著O4也有資格進行垃圾收集,因此我們可以說O3保留的堆為 2kB
  • O2引用了O3。 但是現在要注意,從O2刪除指向O3的指針并不能使O3符合GC的條件,因為O1仍然有指向它的指針。 因此, O2保留的堆只有1kB
  • 另一方面,O1是在此小圖中保留所有引用的對象,因此,如果我們刪除O1,則該圖上的所有內容都將被垃圾回收。 因此, O1保留的堆為4kB

實際上有什么影響? 實際上,了解淺堆大小和保留堆大小之間的差異使使用內存分析器和堆轉儲分析器之類的工具成為可能–例如,如果您不知道如何區分這兩種方法,那么挖掘Eclipse MAT可能被證明是不可能的。堆大小測量的類型。

什么是淺堆?

本文是本系列的第二篇文章,我們將嘗試回答這些問題。 最后一篇文章解釋了對象的保留大小和淺大小之間的區別。 在本文中,我們還提供了一個如何計算數據結構的保留堆大小的示例。 在今天的文章中,我們將擴展上一篇文章中所謂的“簡單”。 即– 什么是以及如何測量對象使用的淺堆。

在第一篇文章中,我們指出了計算淺堆大小很容易–從而僅由對象本身占用的堆組成,從而大大降低了復雜性。 但是,如何計算對象“自身”需要多少內存呢? 顯然有一個公式:

Shallow Heap Size = [reference to the class definition] + space for superclass fields + space for instance fields + [alignment]

似乎不太有用,是嗎? 讓我們嘗試使用以下示例代碼來應用公式:

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;
}

現在,我們努力回答的問題是– Y實例需要多少淺堆大小? 讓我們開始計算它,假設我們使用的是32位x86體系結構:

作為起點– Y是X的子類,因此它的大小包括超類中的“某物”。 因此,在計算Y的大小之前,我們先考慮計算X的淺大小。

跳到X的計算中,前8個字節用于引用其類定義。 該引用始終存在于所有Java對象中,并且被JVM用來定義以下狀態的內存布局。 它還具有三個實例變量–一個int,一個Integer和一個字節。 這些實例變量需要堆,如下所示:

  • 一個字節就是應該的。 內存中有1個字節。
  • 我們的32位架構中的int需要4個字節。
  • 對整數的引用也需要4個字節。 請注意,在計算保留堆時,我們還應考慮包裝到Integer對象中的原語的大小,但是在此處計算淺堆時,我們在計算中僅使用4個字節的參考大小。

那么-是嗎? X的淺堆=從引用到類定義的8個字節+ 1個字節(該字節)+ 4個字節(int)+ 4個字節(對Integer的引用)= 17個字節? 實際上–不 。 現在起作用的是對齊(也稱為填充)。 這意味著JVM以8字節的倍數分配內存,因此如果我們創建X的實例,我們將分配24字節而不是17字節。

如果您可以跟隨我們到這里,那很好,但是現在我們嘗試使事情變得更加復雜。 我們不是在創建X的實例,而是在創建Y的實例。這意味著–我們可以從引用中減去8個字節,以引用類定義和對齊方式。 乍一看可能不太明顯,但是–您是否注意到,在計算X的淺大小時,我們沒有考慮到它也擴展了java.lang.Object,因為即使您未在其中明確聲明它,所有類也會這樣做。您的源代碼? 我們不必考慮超類的標頭大小,因為JVM足夠聰明,可以從類定義本身進行檢查,而不必一直將其復制到對象標頭中。

對齊方式也一樣–創建對象時,您只能對齊一次,而不能在超類/子類定義的邊界對齊。 因此,可以肯定地說,當創建X的子類時,您只會從實例變量繼承9個字節。

最后,我們可以跳到初始任務并開始計算Y的大小。正如我們所看到的,我們已經在超類字段中丟失了9個字節。 讓我們看看實際構造Y實例時將添加什么。

  • Y的標頭引用其類定義占用8個字節。 與以前的相同。
  • 日期是對對象的引用。 4字節。 簡單。
  • 該列表是對集合的引用。 同樣是4個字節。 不重要的。

因此,除了超類中的9個字節之外,我們還有8個字節的頭空間,2×4個字節的數據來自兩個引用(列表和日期)。 Y實例的總淺層大小為25個字節,對齊為32個字節。

為了使計算更容易遵循,我們將其匯總在下圖中:

1個 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 賓語 一個 b C
? 賓語 一個 b C d ?

您可以用這些知識做什么? 加上計算保留堆大小的技巧(在我的最新文章中已經介紹過 ),您現在擁有了計算數據結構實際需要多少內存的最終能力。

為了使事情變得更加有趣,我們創建了一個實用程序,該實用程序可以測量對象的淺堆和保留堆的大小。 在不久的將來,我們將免費提供該工具。 訂閱我們的Twitter feed,敬請關注!

測量,不要猜測

看起來很簡單的任務實際上可能變得有些復雜。 在計算對象的內存占用量時,您需要牢記很多不同方面:

  • 我需要測量淺堆還是保留堆大小?
  • 我是否要針對32位或64位架構進行計算?
  • 我是在x86,SPARC,POWER還是其他無法想象的東西上運行?
  • 是否使用壓縮或未壓縮的普通對象指針?
  • [在此處輸入您擔心或不完全理解的其他內容]

當試圖滿足另一個截止日期時,在嘗試估計數據結構的大小時牢記所有這些方面是完全不合理的。 因此,我們繼續將Java Champion Heinz Kabutz發布的代碼打包為Java代理,并提供了一種輕松的方法將其添加到您的應用程序中。

添加代理使您可以輕松地跟蹤實際環境中數據結構占用的內存量。 并做到了沒有其他選擇所帶來的復雜性。 在下面的四個簡單步驟中,您正在運行并最終了解寶貴的緩存實際消耗了多少內存:

步驟1: 下載代理。 不用擔心,它只有幾千字節。

步驟2:解壓縮下載的代理。 您會看到它與源代碼以及如何使用它的樣例一起打包在一起。 隨意使用代碼。

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:嘗試捆綁的測試用例。 捆綁的測試用例測量的數據結構與我們在博客文章中描述的有關淺堆大小測量的數據結構相同。 對于那些不愿意來回點擊的人,這里再次是代碼:

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測試一起提供,以編譯和運行示例。 如果您使用的是32位體系結構,請運行ant testant test-32 。 使用ant test運行所有測試時,應該看到以下輸出

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位體系結構上,Y的淺堆消耗32個字節,保留堆占用48個字節。 在帶有-XX:-UseCompressedOops的64位體系結構上,淺層大小增加到48個字節,保留堆大小增加到72個字節。 如果您對我們如何計算這些數字感到困惑,那么請從本系列的先前文章中了解什么是以及如何計算淺層和保留堆大小。

步驟4:將代理附加到您自己的Java應用程序。 為此,將-javaagent:path-to/sizeofagent.jar到JVM啟動腳本中。 現在,您可以測量通過調用淺堆消耗MemoryCounterAgent.sizeOf(yourObject)或測量通過調用保留堆消耗MemoryCounterAgent.deepSizeOf(yourObject)直接在你的代碼。 另請參閱捆綁的ant腳本和eu.plumbr.sizeof.test.SizeOfSample類,以防您在執行過程中感到困惑。

當然,您有許多選擇,尤其是以內存分析器和APM解決方案的形式。 但是,這個小型代理將快速完成其任務,幾乎不需要設置或學習。 好吧,至少我們玩得很開心。 而不是處理我們的產品積壓 。

PS。 在撰寫本文時,以下在線資源被用作靈感來源:

  • 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

并且-不要忘了將此代碼發送給Heinz Kabutz,他在2007年3月的Java專家通訊中首次發布了該代碼。

參考: 我需要多少內存(第1部分)–什么是保留堆? , 我需要多少內存(第2部分)–什么是淺堆? , 我需要多少內存(第3部分)–測量,請不要從Plumbr Blog博客的JCG合作伙伴 Nikita Salnikov Tarnovski那里猜到 。

翻譯自: https://www.javacodegeeks.com/2012/12/how-much-memory-do-i-need.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371157.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371157.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371157.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言程序設計預報作業

1閱讀鄒欣老師的博客--師生關系,針對文中的幾種師生關系談談你的看法,你期望的師生關系是什么樣的? 答:我認為文中的師生關系都存在一些缺陷,第一種師生關系是建立在病態關系上的,學生不是植物自然有自己的思想。所以我…

淺談23種設計模式

淺談23種設計模式 類之間的關聯關系:在使用Java、C#和C等編程語言實現關聯關系時,通常將一個類作為另一個類的屬性。   (1)雙向關聯,兩個類互相為各自的屬性,比如顧客類Customer和商品類Product,顧客擁有商品&#x…

網頁布局基礎

1、盒子模型的第一層到第五層: border、padding content、background-image、background-color、margin 2、清除浮動。對受到浮動影響的標簽作以下操作: 1、clear: both; 2、clear: right; clear: left; 3、設置寬度width: 100%(或者固定寬度) overflow…

mysql與串口通信_虛擬機串口與主機串口通信·小程序(下)

上次說到的,不能做到實時通信。那么開兩個進程就可以了,一個用來監聽是否有消息傳來,一個用來等待用戶輸入。那么,先來復習一下進程的相關概念。進程結構linux中進程包含PCB(進程控制塊)、程序以及程序所操縱的數據結構集&#xf…

淺談我所見的CSS命名風格

在兩年工作中,總結一下我所見的css命名風格。 1.單一class命名 .header {width: 500px; } .item {text-indent: 20%; } 優點:簡單,渲染效率高。 缺點:零散,沒有模塊化。 2. 后代選擇器class命名 .header .item a {font…

Java規范請求中的數字

你們都了解Java社區流程 (JCP),不是嗎? JCP是為Java技術開發標準技術規范的機制。 任何人都可以注冊該站點并參與對Java規范請求(JSR)的審查和提供反饋,并且任何人都可以注冊成為JCP成員&#x…

ORACLE MOS 翻譯

http://blog.csdn.net/msdnchina/article/details/53174196轉載于:https://www.cnblogs.com/zengkefu/p/6665950.html

自從我這樣擼代碼以后,公司網頁的瀏覽量提高了107%!

歡迎大家前往騰訊云 社區,獲取更多騰訊海量技術實踐干貨哦~ 本文由騰訊IVWEB團隊發表于云 社區專欄 作者:yangchunwen HTTP協議是前端性能乃至安全中一個非常重要的話題,最近在看《web性能權威指南(High Performance Browser Networking)》&a…

python數列分段_按范圍分段的Python數組

首先,定義你的“極”數第二,根據這些“極”數生成間隔第三,定義盡可能多的列表。在然后,對于每個間隔,掃描列表并在相關列表中添加屬于該間隔的項代碼:source [1, 4, 7, 9, 2, 10, 5, 8]poles (0,3,6,25)…

51nod 1278 相離的圓

基準時間限制:1 秒 空間限制:131072 KB 分值: 10 難度:2級算法題 平面上有N個圓,他們的圓心都在X軸上,給出所有圓的圓心和半徑,求有多少對圓是相離的。例如:4個圓分別位于1, 2, 3, 4的位置&…

讓我們將包變成模塊系統!

使用構建系統將許多項目分為模塊/子項目( Maven , Gradle , SBT …); 編寫模塊化代碼通常是一件好事。 將代碼分為構建模塊主要用于: 隔離代碼部分(減少耦合) api / impl拆分 僅將…

R語言日期的表示和運算(詳細總結)

1、取出當前日期 Sys.Date() [1] "2014-10-29" date() #注意:這種方法返回的是字符串類型 [1] "Wed Oct 29 20:36:07 2014" 2、在R中日期實際是double類型,是從1970年1月1日以來的天數 typeof(Sys.Date()) [1] "double" …

html高度塌陷問題解決

高度塌陷的問題: 當開啟元素的BFC以后,元素將會有如下的特性 1 父元素的垂直外邊距不會和子元素重疊 開啟BFC的元素不會被浮動元素所覆蓋 開啟BFC的元素可以包含浮動的子元素 如何開啟元素的BFC 設置元素浮動 設置元素絕對定位 …

java空格鍵_Java KeyPressed-如果其他鍵也太舊,則無法檢測是否按下了空格鍵

如標題所示,在我的Java游戲中,無法檢測是否同時按下空格鍵和其他鍵。例如,空格鍵是射擊鍵,而箭頭鍵則使玩家移動。如果我按下向上箭頭鍵,向左箭頭鍵和空格鍵,那么它應該向左上方發射子彈。但是,…

How to fix the bug “Expected required, optional, or repeated.”?

參考:https://github.com/tensorflow/models/issues/1834 You need to download protoc version 3.3 (already compiled). Used protoc inside bin directory to run this command like this:tensorflow$ mkdir protoc_3.3tensorflow$ cd protoc_3.3tensorflow/prot…

立面設計模式–設計觀點

在上一篇文章中,我們描述了適配器設計模式 。 在今天的文章中,我們將展示另一種類似的“四結構幫派”模式 。 顧名思義,結構模式用于從許多不同的對象形成更大的對象結構。 外觀模式就是這樣一種模式,它為系統內的一組接口提供了簡…

Java第三次作業 1502 馬 帥

《Java技術》第三次作業 (一)學習總結 1.書中對面向對象封裝性的定義為:指把對象的屬性和行為看成一個密不可分的整體,把不需要讓外界知道的信息隱蔽起來。簡單來說,就是定義的一些對象,只有在本類中才可以…

sass運算

sass具有運算的特性,可以對數值型的Value(如:數字、顏色、變量等)進行加減乘除四則運算。 請注意運算符前后請留一個空格,不然會出錯。 scss.style css.style 本文轉載于:猿2048https://www.mk2048.com/blog/blog.php?idiij12j&titles…

163 coremail_Icoremail企業郵箱

高速穩定iCoremail企業郵箱于國內外多個網絡運營商的主干網數據中心放置郵件服務器,同時采用我司自主研發的Coremail電子郵件系統,從多方面保障了用戶的流暢體驗。安全可靠iCoremail企業郵箱使用歐洲最大的反病毒安全提供商的Sophos反病毒系列產品&#…

jquery-基礎事件[下]

<script>$(function () {mouseover mouseout mouseenter mouseleave的區別$(div).mouseover(function () {$(this).css(background, red);}).mouseout(function () {$(this).css(background, green);});$(div).mouseenter(function () {$(this).css(background, red);}).…