Java堆內存的10個要點

2020-12-16 CSDN技術社區

導讀:對於程式設計師來說,知道堆空間,設置堆空間,處理堆空間的outOfMemoryError錯誤,分析heap dump是非常重要的。文中介紹了Java堆的學習教程以及Java堆內存(heap memory)的十個要點。

文章內容如下:

我剛開始學習Java編程時,可不知道什麼是堆內存或堆空間(heap space),甚至根本不管對象創建時都放在哪裡去了。正式了寫一些程序後,經常會遇到java.lang.outOfMemoryError等錯誤,我才開始關注堆內存。

對大多數程式設計師都經歷過這樣的過程,因為學習一種語言是非常容易來的,但是學習基礎是非常難的,因為沒有什麼特定的流程讓你學習編程的每個基礎,使你發覺編程的秘訣。

對於程式設計師來說,知道堆空間,設置堆空間,處理堆空間的outOfMemoryError錯誤,分析heap dump是非常重要的。這個關於Java堆的教程是給我剛開始學編程的兄弟看的。如果你知道這個基礎知識或者知道底層發生了什麼,當然可能幫助不是那麼大。除非你知道了對象被創建在堆中,否則你不會意識到OutOfMemoryError是發生在堆空間中的。我儘可能的將我所知道的所有關於堆的知識都寫下來了,也希望你們能夠儘可能多的貢獻和分享你的知識,以便可以讓其他人也受益。

Java中的堆空間是什麼?

當Java程序開始運行時,JVM會從作業系統獲取一些內存。JVM使用這些內存,這些內存的一部分就是堆內存。堆內存通常在存儲地址的底層,向上排列。當一個對象通過new關鍵字或通過其他方式創建後,對象從堆中獲得內存。當對象不再使用了,被當做垃圾回收掉後,這些內存又重新回到堆內存中。要學習垃圾回收,請閱讀」Java中垃圾回收的工作原理」。

如何增加Java堆空間

在大多數32位機、Sun的JVM上,Java的堆空間默認的大小為128MB,但也有例外,例如在32未Solaris作業系統(SPARC平臺版本)上,默認的最大堆空間和起始堆空間大小為 -Xms=3670K 和 -Xmx=64M。對於64位作業系統,一般堆空間大小增加約30%。但你使用Java 1.5的throughput垃圾回收器,默認最大的堆大小為物理內存的四分之一,而起始堆大小為物理內存的十六分之一。要想知道默認的堆大小的方法,可以用默認的設置參數打開一個程序,使用JConsole(JDK 1.5之後都支持)來查看,在VM Summary頁面可以看到最大的堆大小。

用這種方法你可以根據你的程序的需要來改變堆內存大小,我強烈建議採用這種方法而不是默認值。如果你的程序很大,有很多對象需要被創建的話,你可以用-Xms and -Xmx這兩個參數來改變堆內存的大小。Xms表示起始的堆內存大小,Xmx表示最大的堆內存的大小。另外有一個參數 -Xmn,它表示new generation(後面會提到)的大小。有一件事你需要注意,你不能任意改變堆內存的大小,你只能在啟動JVM時設定它。

堆和垃圾回收

我們知道對象創建在堆內存中,垃圾回收這樣一個進程,它將已死對象清除出堆空間,並將這些內存再還給堆。為了給垃圾回收器使用,堆主要分成三個區域,分別叫作New Generation,Old Generation或叫Tenured Generation,以及Perm space。New Generation是用來存放新建的對象的空間,在對象新建的時候被使用。如果長時間還使用的話,它們會被垃圾回收器移動到Old Generation(或叫Tenured Generation)。Perm space是JVM存放Meta數據的地方,例如類,方法,字符串池和類級別的詳細信息。你可以查看「Java中垃圾回收的工作原理」來獲得更多關於堆和垃圾回收的信息。

Java堆中的OutOfMemoryError錯誤

當JVM啟動時,使用了-Xms 參數設置的對內存。當程序繼續進行,創建更多對象,JVM開始擴大堆內存以容納更多對象。JVM也會使用垃圾回收器來回收內存。當快達到-Xmx設置的最大堆內存時,如果沒有更多的內存可被分配給新對象的話,JVM就會拋出java.lang.outofmemoryerror,你的程序就會當掉。在拋出 OutOfMemoryError之前,JVM會嘗試著用垃圾回收器來釋放足夠的空間,但是發現仍舊沒有足夠的空間時,就會拋出這個錯誤。為了解決這個問題,你需要清楚你的程序對象的信息,例如,你創建了哪些對象,哪些對象佔用了多少空間等等。你可以使用profiler或者堆分析器來處理 OutOfMemoryError錯誤。」java.lang.OutOfMemoryError: Java heap space」表示堆沒有足夠的空間了,不能繼續擴大了。」java.lang.OutOfMemoryError: PermGen space」表示permanent generation已經裝滿了,你的程序不能再裝在類或者再分配一個字符串了。

Java Heap dump

Heap dump是在某一時間對Java堆內存的快照。它對於分析堆內存或處理內存洩露和Java.lang.outofmemoryerror錯誤是非常有用的。在JDK中有一些工具可以幫你獲取heap dump,也有一些堆分析工具來幫你分析heap dump。你可以用「jmap」來獲取heap dump,它幫你創建heap dump文件,然後,你可以用「jhat」(堆分析工具)來分析這些heap dump。

Java堆內存(heap memory)的十個要點:

1. Java堆內存是作業系統分配給JVM的內存的一部分。

2. 當我們創建對象時,它們存儲在Java堆內存中。

3. 為了便於垃圾回收,Java堆空間分成三個區域,分別叫作New Generation, Old Generation或叫作Tenured Generation,還有Perm Space。

4. 你可以通過用JVM的命令行選項 -Xms, -Xmx, -Xmn來調整Java堆空間的大小。不要忘了在大小後面加上」M」或者」G」來表示單位。舉個例子,你可以用 -Xmx256m來設置堆內存最大的大小為256MB。

5. 你可以用JConsole或者 Runtime.maxMemory(), Runtime.totalMemory(), Runtime.freeMemory()來查看Java中堆內存的大小。

6. 你可以使用命令「jmap」來獲得heap dump,用「jhat」來分析heap dump。

7. Java堆空間不同於棧空間,棧空間是用來儲存調用棧和局部變量的。

8. Java垃圾回收器是用來將死掉的對象(不再使用的對象)所佔用的內存回收回來,再釋放到Java堆空間中。

9. 當你遇到java.lang.outOfMemoryError時,不要緊張,有時候僅僅增加堆空間就可以了,但如果經常出現的話,就要看看Java程序中是不是存在內存洩露了。

10. 請使用Profiler和Heap dump分析工具來查看Java堆空間,可以查看給每個對象分配了多少內存。

文章出自:java revisited (無法直接訪問)

譯文出自:伯樂在線

相關焦點

  • 如何準確理解Java中的堆與棧
    關於內存可以說是Java中的重要概念,而棧和堆又是內存中的兩個重要部分。怎樣理解棧和堆?棧可以理解為內存中一片連續的區域,而堆可以理解為內存中一片分散的區域。可以說,棧是用來運行程序的區域,當在棧裡應用一個值的時候,這個值就會指向堆中的一個位置。其實可以理解為一種函數關係。
  • 堆與棧:JAVA和c++內存分配的區別
    靜態存儲分配要求在編譯時能知道所有變量的存儲要求,棧式存儲分配要求在過程的進口處必需知道所有的存儲要求,而堆式存儲分配則專門負責在編譯時或運行時模塊進口處都無法確定存儲要求的數據結構的內存分配,好比可變長度串和對象實例。堆由年夜片的可操作塊或餘暇塊組成,堆中的內存可以按照肆意挨次分配和釋放。
  • 深入分析Java虛擬機堆和棧及OutOfMemory異常產生原因
    Heap(堆)堆是Java虛擬機所管理內存中最大的一塊,在虛擬機啟動時創建,被所有線程共享。堆在虛擬機啟動時創建,用於存儲所有的對象實例和數組(在某些特殊情況下不是)。堆中的對象永遠不會顯式地釋放,必須由GC自動回收。
  • 認識Java虛擬機的堆和棧
    關於運行數據區的堆堆是在運行數據區劃分出來的一塊內存區域,用於存儲在程序運行過程中創建的對象實例和數組,在虛擬機運行的所有線程創建的對象實例和數組都共享一個堆。堆中的存儲空間是有限的,當堆中存儲的對象實例超過堆的存儲空間時,堆就無法再存儲新的實例對象,在這種情況下就會造成堆的溢出,java程序也會拋出內存溢出異常。因此當堆中的實例對象不再需要時,應及時回收空間,回收的空間再分配給新的實例對象。那麼,在什麼情況下要對堆中的實例對象進行回收呢?
  • JVM中的五大內存區域劃分詳解及快速掃盲
    2.內存如何管理?3.線程資源如何利用?腦袋裡有個印象即可,帶著問題去學習。4. 運行java文件的大概流程想要運行java的源文件,必須要經過javac編譯器編譯成.class文件,也就是字節碼文件。
  • 零基礎java入門教程java數組選擇排序冒泡排序和java內置排序
    0基礎java入門 java數組的排序:選擇排序選擇排序:就是對給定的數組數據進行從大到小或從小到大的順序排好,而內思路則是比如講第一個元素和後面所有元素進行對比,然後將最大或最小的和頭角標兌換位置,然後再用第二個元素和剩下的依次對比,然後再兌換位置,如此循環。
  • java中棧(stack)堆(heap)靜態區(static area)概念
    對於java的這3大區域了解下還是有必要的,尤其是對jvm調優,更應該理解下它們的概念。棧(stack):對象實例在heap 中分配好以後,需要在stack中保存一個4位元組的heap內存地址,用來定位該對象實例在heap 中的位置,便於找到該對象實例。
  • Java面試總結之Full GC
    掌握了這3個要點,full gc相關的問題就易如反掌了。一、gc的定義GC,即就是Java垃圾回收機制。目前主流的JVM(HotSpot)採用的是分代收集算法。與C++不同的是,Java採用的是類似於樹形結構的可達性分析法來判斷對象是否還存在引用。
  • JVM內存區域之線程私有區域
    不過,也正是java把控制內存的權力交給了java虛擬機,一旦出現內存洩漏和內存溢出方面的問題,如果不了解虛擬機是怎麼使用內存的,那排查錯誤、修正問題將會成為一項異常艱難的工作。運行時數據區:java虛擬機在執行java程序的過程中會把它所管理的內存劃分為若干個不同的數據區域。
  • 2020第一篇:堆、棧、方法區、類加載器——JVM 內存模型分析
    在美好的祝願中,咱們開始今年的第一篇分享:JVM內存模型。JVM 內存模型看過上圖,應該對jvm有了一個大概的了解,如果沒看懂也不要緊,慢慢聽我來一一解釋圖中的這些組件:JVM內存劃分,是人為的根據不同內存空間的存儲特點以及存儲的數據而劃分的不同邏輯內存區域
  • 系統內存佔用較高?
    那麼,現在得到一個初步的結論就是:不管是該jvm進程用到的堆內存還是堆外內存,都很小(相對於top命令顯式的18% * 8G佔用量而言)。所以是否可以猜想:jvm只是向作業系統申請了這麼多內存暫時沒有歸還回去,留待下次線程池有新任務時繼續復用呢?本文最後一部分試驗就圍繞著一點展開。
  • 「原創」JVM系列02|Java虛擬機結構
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫Java虛擬機學習 Java 虛擬機,先要掌握其基本結構,了解各部分有什麼作用,各部分之間是如何協調工作的。
  • 堆和棧的區分
    不管你是學習c語言,還是學習c++,亦或是學習java,你都會遇到內存分配的問題,而對於內存分配,它其實有兩個地方,一個地方叫做堆,一個地方叫做棧,什麼時候將數據存放到堆上面,什麼時候將數據存放到棧上面,它們的區別是什麼,今天我們就來詳細講解一下。
  • Java基本數據類型
    實際上,JAVA中還存在另外一種基本類型void,它也有對應的包裝類 java.lang.Void,不過我們無法直接對它們進行操作。,在內在中佔32位,即4個字節,取值範圍-2147483648~2147483647,默認值0long:長整型,在內存中佔64位,即8個字節-2^63~2^63-1,默認值0Lfloat:浮點型,在內存中佔32位,即4個字節,用於存儲帶小數點的數字(與double的區別在於float類型有效小數點只有6~7位),默認值0
  • 一張圖讀懂jvm之運行時數據區-堆、棧、以及程序計數器
    你知道 java 程序在運行時數據是存儲在哪裡的嗎?比如,常量數據,臨時計算結果,你知道棧溢出和內存不足是怎麼一回事嗎?關注我,帶你一起走進 jvm,原創不易,記得關注 + 收藏哦。下面,我們來看下這張圖:運行時數據區分為:pc(program counter)寄存器、java 虛擬機棧、堆、方法區、運行時常量池、本地方法棧。其中,運行時常量池屬於方法區,下面是各自的詳細介紹。
  • 關於PHP語言在內存中的分配(堆和棧的區別)
    分享關於編程中的數據在內存裡的存儲方式,本文以PHP語言為例來分析計算機中各段存儲區的區別,代碼段、堆空間段、代碼段、初始化靜態常量段。棧空間段:是存儲佔用相同空間長度並且佔用空間小的數據類型的地方,比如說整型1,10,100,1000,10000,100000 等等,在內存裡面佔用空間是等長的,都是64 位4 個字節。存儲的都是局部變量,凡是定義在方法中的都是局部變量(方法外的是全局變量),變量有自己的作用域,一旦離開作用域,變量就會被釋放。
  • Java 15 即將到來,新特性速覽!
    在發布前夕,我們不妨先一窺新版 JDK 的新特性:第二個外部內存訪問 API(孵化階段),它將使 Java 程序安全高效地訪問 Java 堆以外的外部存儲器。該 API 應該能夠在各種外部內存(如本機、持久和託管堆)上進行操作。
  • Java基礎面試題簡單總結
    答:是能夠定義成為一個中文的,因為java中以unicode編碼,一個char佔16個字節,所以放一個中文是沒問題的29、GC是什麼?並考慮2種回收機制答:Java語言中一個顯著的特點就是引入了垃圾回收機制,使c++程式設計師最頭疼的內存管理的問題迎刃而解,它使得Java程式設計師在編寫程序的時候不再需要考慮內存管理。由於有個垃圾回收機制,Java中的對象不再有"作用域"的概念,只有對象的引用才有"作用域"。
  • Java中的volatile變量適合於什麼場景下應用
    為什麼這個值不對,大家都知道java是值傳遞,JVM在運行時內存分配匯總有一個內存區域稱為虛擬機棧, 線程棧保存了線程運行時的信息,當線程訪問某個對象的值的時候,首先通過對象的引用找到對應在堆內存的變量的值,然後把堆內存變量的值load到本地內存中(當前線程所分配內存區域),建立一個變量副本, 之後線程不再和對象在堆內存的變量有任何聯繫,而是直接修改副本的值,在修改完成之後自動把變量副本寫回堆內存,
  • 「原創」JVM系列03|Java棧—方法是如何調用的?
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫本文是何適 JVM 修仙系列第 3 篇,文末有本系列文章匯總。舉例說明:方法1中調用方法2,方法2中調用方法3,方法3中調用方法4,當執行到方法4時,棧內存結構如下圖:舉例模擬棧溢出:因為每次方法調用都會生成一個棧幀,當函數調用數量很大,生成的棧幀內存超過 Java 棧總內存時,就會棧溢出 StackOverflowError