使用未初始化的內存是什么意思_他們都說JVM能實際使用的內存比-Xmx指定的少?這是為什么呢...

這確實是個挺奇怪的問題,特別是當最常出現的幾種解釋理由都被排除后,看來JVM并沒有耍一些明顯的小花招:

  • -Xmx和-Xms是相等的,因此檢測結果并不會因為堆內存增加而在運行時有所變化。
  • 通過關閉自適應調整策略(-XX:-UseAdaptiveSizePolicy),JVM已經事先被禁止動態調整內存池的大小。

重現差異檢測結果

要弄清楚這個問題的第一步就是要明白這些工具的實現原理。通過標準APIs,我們可以用以下簡單語句得到可使用的內存信息。

System.out.println("Runtime.getRuntime().maxMemory()="+Runtime.getRuntime().maxMemory());

而且確實,現有檢測工具底層也是用這個語句來進行檢測。要解決這個問題,首先我們需要一個可重復使用的測試用例。因此,我寫了下面這段代碼:

package?eu.plumbr.test;//imports?skipped?for?brevitypublic?class?HeapSizeDifferences?{??static?Collection?objects?=?new?ArrayList();??static?long?lastMaxMemory?=?0;??public?static?void?main(String[]?args)?{????try?{??????List?inputArguments?=?ManagementFactory.getRuntimeMXBean().getInputArguments();??????System.out.println("Running?with:?"?+?inputArguments);??????while?(true)?{????????printMaxMemory();????????consumeSpace();??????}????}?catch?(OutOfMemoryError?e)?{??????freeSpace();??????printMaxMemory();????}??}??static?void?printMaxMemory()?{????long?currentMaxMemory?=?Runtime.getRuntime().maxMemory();????if?(currentMaxMemory?!=?lastMaxMemory)?{??????lastMaxMemory?=?currentMaxMemory;??????System.out.format("Runtime.getRuntime().maxMemory():?%,dK.%n",?currentMaxMemory?/?1024);????}??}??static?void?consumeSpace()?{????objects.add(new?int[1_000_000]);??}??static?void?freeSpace()?{????objects.clear();??}}

這段代碼通過將new int[1_000_000]置于一個循環中來不斷分配內存給程序,然后監測JVM運行期的當前可用內存。當程序監測到可用內存大小發生變化時,通過打印出Runtime.getRuntime().maxMemory()返回值來得到當前可用內存尺寸,輸出類似下面語句:

Running?with:?[-Xms2048M,?-Xmx2048M]Runtime.getRuntime().maxMemory():?2,010,112K.

實際情況也確實如預估的那樣,盡管我已經給JVM預先指定分配了2G對內存,在不知道為什么在運行期有85M內存不見了。你大可以把 Runtime.getRuntime().maxMemory()的返回值2,010,112K 除以1024來轉換成MB,那樣你將得到1,963M,正好和2048M差85M。

找到根本原因

在成功重現了這個問題之后,我嘗試用使用不同的GC算法,果然檢測結果也不盡相同。

1d5a90f3bbe30644d7c242bcaf6d5507.png

除了G1算法剛好完整使用了我預指定分配的2G之外,其余每種GC算法似乎都不同程度地丟失了一些內存。

現在我們就該看看在JVM的源代碼中有沒有關于這個問題的解釋了。我在CollectedHeap這個類的源代碼中找到了如下的解釋:

??Running?with:?[-Xms2048M,?-Xmx2048M]??//?Support?for?java.lang.Runtime.maxMemory():??return?the?maximum?amount?of??//?memory?that?the?vm?could?make?available?for?storing?'normal'?java?objects.??//?This?is?based?on?the?reserved?address?space,?but?should?not?include?space??//?that?the?vm?uses?internally?for?bookkeeping?or?temporary?storage??//?(e.g.,?in?the?case?of?the?young?gen,?one?of?the?survivor??//?spaces).??virtual?size_t?max_capacity()?const?=?0;

我不得不說這個答案藏得有點深,但是只要你有足夠的好奇心,還是不難發現的:有時候,有一塊Survivor區是不被計算到可用內存中的。

69436330f4dc51be26f21fcd294aa685.png

明白這一點之后問題就好解決了。打開并查看GC logging 信息之后我們發現,在Serial,Parallel以及CMS算法回收過程中丟失的那些內存,尺寸剛好等于JVM從2G堆內存中劃分給Survivor區內存的尺寸。例如,在上面的ParallelGC算法運行時,GC logging信息如下:

Running?with:?[-Xms2g,?-Xmx2g,?-XX:+UseParallelGC,?-XX:+PrintGCDetails]Runtime.getRuntime().maxMemory():?2,010,112K....?rest?of?the?GC?log?skipped?for?brevity?...?PSYoungGen??????total?611840K,?used?524800K?[0x0000000795580000,?0x00000007c0000000,?0x00000007c0000000)??eden?space?524800K,?100%?used?[0x0000000795580000,0x00000007b5600000,0x00000007b5600000)??from?space?87040K,?0%?used?[0x00000007bab00000,0x00000007bab00000,0x00000007c0000000)??to???space?87040K,?0%?used?[0x00000007b5600000,0x00000007b5600000,0x00000007bab00000)?ParOldGen???????total?1398272K,?used?1394966K?[0x0000000740000000,?0x0000000795580000,?0x0000000795580000)

由上面的信息可以看出,Eden區被分配了524,800K,兩個Survivor區都被分配到了87,040K,老年代(Old space)則被分配了1,398,272K。把Eden區、老年代以及一個Survivor區的尺寸求和,剛好等于2,010,112K,說明丟失的那85M(87,040K)確實就是剩下的那個Survivor區。

總結

讀完這篇帖子的你現在應該對如何探索Java API的實現原理有了一些新的想法。下次當你用某個可視化工具查看可用堆內存發現所得的結果略少于-Xmx指定分配的大小時,你就知道這兩者之間的差值是一塊Survivor區的大小。

私信回復 資料 領取一線大廠Java面試題總結+阿里巴巴泰山手冊+各知識點學習思維導+一份300頁pdf文檔的Java核心知識點總結!

這些資料的內容都是面試時面試官必問的知識點,篇章包括了很多知識點,其中包括了有基礎知識、Java集合、JVM、多線程并發、spring原理、微服務、Netty 與RPC 、Kafka、日記、設計模式、Java算法、數據庫、Zookeeper、分布式緩存、數據結構等等。

我必須承認這個知識點在日常編程中并不是特別常用,但這并不是這篇帖子的重點。我寫下這篇帖子是為了描述一種特質,一種我經常在優秀的程序員身上尋找的特質-好奇心。好的程序員們會經常試著去了解一些事物工作的機理以及原因。有時問題的答案并不會那么顯而易見,但是希望你能堅持尋找下去,最終在尋找過程中的所累積的知識總會讓你獲益匪淺。

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

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

相關文章

定義整型數組_C語言基礎-數組怎么用

到目前為止,我們了解到C語言中可以使用整型,浮點型和字符型的數據類型來描述我們人類世界的各種數據,但是這些還遠遠不夠……我們在IOT領域經常會遇到這樣一個數據使用場景:某天的固定時間內,會有多臺(我們…

找出一個字符串中出現次數最多的字_海量數據中找出前k大數(topk問題)

在海量數據中找出出現頻率最好的前k個數,或者從海量數據中找出最大的前k個數,這類問題通常被稱為top K問題。針對top K類問題,通常比較好的方案是分治Trie樹/hash小頂堆(就是上面提到的最小堆),即先將數據集…

crowd counting_[crowd_counting]-SFCN-CVPR2019amp;amp;GCC dataset

1.Contribution(1)主要是提出了基于GTA5的GCC數據集數據集下載地址:https://gjy3035.github.io/GCC-CL/?gjy3035.github.io(2)提出了在如何在GCC上train,然后在傳統的通用數據集上test的遷移學習方案&…

代碼更換ui圖片_用技術的方式,在UI設計稿中設置隨機碼,保證高清

本文首發于:行者AI 在工作中會遇到批量給圖片添加文字,隨機碼等需求,當數據碼數量較大時,UI的工作量就會非常大,這時候我們可以用python來幫我們提高工作效率。1. 需求分析我們有這樣一張圖片,我們需要將一…

hash地址_redis中的hash擴容、漸進式rehash過程

背景: redis字典(hash表)當數據越來越多的時候,就會發生擴容,也就是rehash對比:java中的hashmap,當數據數量達到閾值的時候(0.75),就會發生rehash,hash表長度變為原來的二…

是什么牌子_水晶項鏈什么牌子好

閱讀本文前,請您先點擊上面的藍色字體,再點擊“關注”,這樣您就可以免費收到最新內容了。每天都有分享,完全是免費訂閱,請放心關注! …

什么是機器人的五點校正法_機器人校正方法

機器人校正方法【專利說明】機器人校正方法[0001]本申請案主張于2012年9月18日申請之美國臨時專利申請案第61/702,377號的優先權,所述專利申請案的揭示完整結合于此以供參考。技術領域[0002]本發明涉及一種工件加工,尤其涉及一種用于工件加工…

stn算子_深度學習常用算子(二)

1、Tensor維度變換1)Flatten作用:將輸入tensor中從start_axis維度到end_axis維度合并為1維2)Reshape作用:將輸入Tensor描述轉換為新的shape3)FreespaceExtract作用:將h維變成1,其他維度不變,從而完成對h的采樣&#xf…

iframe異步加載_5種延遲加載圖像的方法以幫助你提升網站性能與用戶體驗

英文 | https://www.sitepoint.com/five-techniques-lazy-load-images-website-performance/翻譯 | web前端開發(ID:web_qdkf)由于圖像是Web上最流行也是必不可少的內容類型之一,因此網站上的圖片頁面加載時間很容易成為一個問題。即使進行了適當的優化&…

ubuntu18安裝python3.6.8_ubuntu 18.04 + Python 3.6.8 更換軟件安裝源

國外的開源項目開展的是如火如荼,我們國內的當然也不甘落后。為了更好的玩轉 Python,我使用了 ubuntu Linux 來作為開發環境。但是由于國內網絡的限制,訪問國外的一些軟件源的時候,速度比較慢,這時我們需要更換成國內的…

springframework報錯_應對報錯信息的必殺技!

今天遇到了一個錯誤,一般的錯誤提示會很明顯,一看就知道是什么問題。今天遇到的這個說實話真的不好找原因,一般在這種情況下該怎么解決呢?分享下我的思路吧,不一定是最好的,至少有用。直接上圖吧&#xff0…

電腦運行卡頓怎么處理_【眾點學】電腦運行PS卡頓?可能是你的虛擬內存沒設置好!...

不少小伙伴都遇到過這樣的煩惱明明自己的電腦擁有大內存PS用著用著就卡頓了經過教體君的仔(bai)細(du)研(yi)究(xia)發現原來電腦的 虛擬內存 只有2G當我們用大型軟件或玩大型游戲電腦越用越卡時該怎么做?今天【眾點學】我們一起來看看Win7和Win10系統下分別如何設置…

線程池拒絕策略 開發中常用什么策略_面試官:說說你知道多少種線程池拒絕策略...

往期文章為什么阿里Java規約要求謹慎使用SimpleDateFormathttps://www.toutiao.com/i6696127929048367629/為什么我強烈推薦你用枚舉來實現單例模式https://www.toutiao.com/i6696861933687013901/為什么不要在MySQL中使用UTF-8編碼方式https://www.toutiao.com/i6697966437727…

css html 雙面打印_從 Linux 命令行進行打印 | Linux 中國

導讀:在 Linux 命令行進行打印的內容比單單一個 lp 命令多得多,讓我們來看一些可用選項。       本文字數:4305,閱讀時長大約:5分鐘https://linux.cn/article-13012-1.html作者:Sandra Henry-stocker譯…

python保存快捷鍵是什么_python常用快捷鍵

最重要的快捷鍵1. ctrlshiftA:萬能命令行2. shift兩次:查看資源文件新建工程第一步操作1. module設置把空包分層去掉,compact empty middle package2. 設置當前的工程是utf-8,設置的Editor-->File Encodings-->全部改成utf-8,注釋1. ctrl/:單行注釋光標操作1. ctrlaltent…

服務器內存超限問題_服務器內存爆滿最佳處置方案

內存爆滿截圖:分析:內存持續飆升,應該是有大量內存一直沒有釋放,考慮僵尸對象,僵尸進程,最簡單的就是重啟服務器,但是就無法找到罪魁禍首了。驗證:top命令查看活躍進程的資源使用情況…

js map對象遍歷_何時使用 Map 來代替變通的 JS 對象

JS 普通對象 {key: value} 用于存放結構化數據。但有一件事我覺得很煩:對象鍵必須是字符串(或很少使用的 symbol)。如果將數字用作鍵會怎樣?在這種情況下不會有錯誤:const names { 1: One, 2: Two,};Object.keys(names); // > [1, 2]JS 會隱式地將…

mysql怎么顯示結果窗口_mysql8中窗口函數

在以前的MySQL版本中是沒有窗口函數的,直到MySQL8.0才引入了窗口函數。窗口函數是對查詢中的每一條記錄執行一個計算,并且這個計算結果是用與該條記錄相關的多條記錄得到的。1.窗口函數與聚合函數窗口函數與聚合函數很像,他們都是在一組記錄而…

python控制臺輸入字符串作為參數_Python-如何將字符串傳遞到subprocess.Popen(使用stdin參數)?...

小編典典Popen.communicate() 說明文件:請注意,如果要將數據發送到進程的stdin,則需要使用stdin PIPE創建Popen對象。同樣,要在結果元組中獲得除None以外的任何內容,你還需要提供stdout PIPE和/或stderr PIPE。替換…

log4jdbc mysql_[簡單]log4jdbc-log4j2配置簡記_MySQL

log4jdbc-log4j2,就不多說了,不了解的可以谷歌,附上log4jdbc-log4j2的官方鏈接:https://code.google.com/p/log4jdbc-log4j2/ ,上面有非常詳細的介紹。簡單的貼下配置文件,其他的見附件:databas…