java jvm内存地址_深入Java虚拟机——JVM内存详解
在C++中,程序員擁有每一個對象的所有權,但與此同時還肩負著釋放對象內存空間的責任;而Java由于有了虛擬機的幫助,程序員擁有對象的所有權的同時不再需要釋放對象的內存空間。由于是JVM自動進行對象內存的釋放,所以內存泄漏和內存溢出的問題也很少出現。
Java虛擬機在運行時將內存空間分成5個部分,分別是:方法區、虛擬機棧、本地方法棧、堆、程序計數器。
程序計數器
本質
程序計數器本質上是一塊較小的內存空間。
作用
可以把程序計數器簡單地看作是當前線程所執行的字節碼的行號指示器。
字節碼解釋器在工作時,通過改變程序計數器的值來選取下一條需要執行的字節碼指令。
除此之外,程序的分支、循環、跳轉、異常處理、線程恢復等基本功能都需要依賴程序計數器來完成。
特性
程序計數器是一個個線程私有內存。每個線程都私有一個程序計數器,用來記錄線程當前執行的位置,好讓線程恢復執行的時候知道上一次執行的位置。所以各個線程之間的計數器相互獨立,互補影響。
若線程正在執行的是一個Java方法,那么當前線程的程序計數器記錄的是正在執行的虛擬機字節碼指令的地址;若線程正在執行的是一個Native方法,則這個計數器值為空。
PS:Native方法是指不使用Java語言寫的方法,或者是使用Java語言寫的直接操控計算機硬件的方法。
Java虛擬機棧
是什么?
JVM棧是用來描述Java方法執行過程的一個內存模型。
JVM棧中存放著一個個棧幀,每個棧幀都對應著一個Java方法。
當一個Java方法被執行時,JVM會在JVM棧中創建一個棧幀,用于存儲:局部變量表、操作數棧、動態鏈接、方法出口等信息。
每一個Java方法被調用到執行完成的過程,都對應著一個個棧幀在JVM棧中的入棧和出棧。
特性
JVM棧是線程私有的,每一個線程擁有一個獨立的JVM棧,這個線程中所要執行的方法就會在它所對應的JVM棧中創建棧幀。
通常所說的“堆“和“棧“
有人把JVM所使用的內存分為棧內存和堆內存,這種分法比較粗糙。
這種分法中所說的“棧“其實僅僅是JVM棧中一個個棧幀中的局部變量表。
棧幀中的局部變量表
局部變量表中存放著編譯時期可知的各種基本數據類型、對象引用、returnAddress類型。
局部變量表所需的內存空間在編譯時期完成分配,一個方法所需分配多大的局部變量表是完全確定的,局部變量表的大小在程序運行時不會改變。
PS:對象引用也叫做reference類型,它的本質是一個地址,并不是對象本身,不同的虛擬機這個地址指向的內容也不一樣;這個指針可能指向一個對象的起始地址,也可能指向一個代表對象的句柄。
PS:returnAddress類型本質上是一個地址,這個地址指向一條字節碼執行。
Java虛擬機棧可能可能產生的異常
若線程請求的棧深度大于虛擬機所允許的最大深度,就拋出StackOverFlow異常;
若虛擬機棧可以動態擴展,沒有最大深度的限制,當內存已經用完,無法再擴展棧深度時,就拋出OutOfMemory異常。
本地方法棧
本地方法棧的特性和JVM棧的特性幾乎一樣,只不過JVM棧中存放的是Java方法的相關信息,而本地方法棧中存放的是本地方法的相關信息。
本地方法棧也會拋出OutOfMemoryError和StackOverFlow異常。
堆
是什么?
堆內存的唯一目的就是存放所有的對象實例。
特性
堆內存是Java虛擬機所需要的內存中最大的一塊內存。
它是被所有線程共享的一塊內存區域。
堆內存物理上不一定要連續,只需要邏輯上連續即可。
堆與垃圾回收的關系?
堆內存是垃圾回收的主要區域,所以也被稱為GC堆。
堆可能拋出的異常
若堆中的實例都是有用的,并且內存已經用完時,就會發生OutOfMemoryError異常。
方法區
是什么?
方法區也是JVM需要使用的一塊內存區域,它用來存儲已經被JVM加載的類的信息、常量、靜態變量、編譯后的代碼等數據。
特性
方法區和堆一樣是各個線程共享的內存區域。
它在物理上不需要連續的內存空間。
方法區的大小可以固定,也可以可擴展。
方法區可以不實現垃圾收集。
可以不實現垃圾收集,那么方法區中的數據就永久存在嗎?
不是的。方法區中的垃圾收集行為比較少見,但并非數據進入方法區就永久存在了。
方法區的內存回收的主要目標是對常量池的回收和對類型的卸載。
方法區可能拋出的異常
當方法區無法滿足內存分配需求的時候就拋出OutOfMemoryError異常。
運行時常量池
a)是什么?
運行時常量池是方法區的一部分。
我們知道,.java文件被編譯之后生成的.class文件中除了包含:類的版本、字段、方法、接口等信息外,還有一項就是常量池,常量池中存放編譯時期產生的各種字面量和符號引用,.class文件中的常量池中的所有的內容在類被加載后存放到方法區的運行時常量池中。
PS:int age = 21;//age是一個變量,可以被賦值;21就是一個字面值常量,不能被賦值;
int final pai = 3.14;//pai就是一個符號常量,一旦被賦值之后就不能被修改。
b)特性
.class文件中的常量池具有動態性。Java并不要求常量只能在編譯時候產生,在運行時就不能增加了;Java允許在運行期間將新的常量放入方法區的運行時常量池中。
Java中String類中的intern方法就是采用了運行時常量池的動態性。當調用 intern 方法時,如果池已經包含一個等于此 String 對象的字符串,則返回池中的字符串。否則,將此 String 對象添加到池中,并返回此 String 對象的引用。
c)可能拋出的異常
運行時常量池是方法區的一部分,所以會受到方法區內存的限制,因此當常量池無法再申請到內存時就會拋出OutOfMemoryError異常。
直接內存
直接內存不是JVM規范中定義的內存區域,但在JVM的實際運行過程中會頻繁地使用這塊區域。而且也會導致OutOfMemoryError異常。
在JDK 1.4中新加入了NIO=New Input/Output類,引入了一種基于通道和緩沖區的IO方式,它可以使用本地函數直接分配堆外內存,然后通過一個存儲在堆里的DirectByteBuffer對象作為這塊內存的引用來操作堆外內存中的數據。這樣能在一些場景中顯著提升性能,因為避免了在Java堆和Native堆中來回復制數據。
直接內存不受Java堆大小的限制,但仍然受本機總內存的限制。
總結
以上是生活随笔為你收集整理的java jvm内存地址_深入Java虚拟机——JVM内存详解的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: java null 对象吗_java中n
- 下一篇: java获取excle表格对象_Java
