一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - java虛擬機深入學習之內存管理機制

java虛擬機深入學習之內存管理機制

2021-06-11 14:02blueskyli Java教程

java虛擬機在程序運行時將內存劃分為多個區域,每個區域作用,生命周期各不相同,下面這篇文章主要給大家介紹了關于java虛擬機深入學習之內存管理機制的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下

前言

前面說過了類的加載機制,里面講到了類的初始化中時用到了一部分內存管理的知識,這里讓我們來看下java虛擬機是如何管理內存的。

先讓我們來看張圖

java虛擬機深入學習之內存管理機制

有些文章中對線程隔離區還稱之為線程獨占區,其實是一個意思了。下面讓我們來詳細介紹下這五部分;

運行時數據區

java虛擬機在執行java程序的過程中會把它所管理的內存劃分為若干個不同的數據區域,這些區域都擁有自己的用途,并隨著jvm進程的啟動或者用戶線程的啟動和結束建立和銷毀。

先讓我們了解下進程和線程的區別:

進程是資源分配的最小單位,線程是程序執行的最小單位。

進程有自己的獨立地址空間,每啟動一個進程,系統就會為它分配一個地址空間、建立數據表來維護代碼段、堆棧段和數據段,這種操作非常昂貴。而線程是共享進程中的數據的,使用相同的地址空間,因此cpu切換一個線程的花費要比進程小很多,同時創建一個線程的開銷也要比進程小很多。

同一個進程中可以包括多個線程,并且線程共享整個進程的資源(寄存器、堆棧、上下文),一個進程至少包含一個線程。線程之間的通信更加方便,同一進程下的線程共享全局變量、靜態變量等數據,而進程之間的通信則需要以通信的方式(ipc)進行。

這里引用在知乎中某位同學的解釋,

進程的顆粒度太大,每次都要有上下的調入,保存,調出。如果我們把進程比喻為一個運行在電腦上的軟件,那么一個軟件的執行不可能是一條邏輯執行的,必定有多個分支和多個程序段,就好比要實現程序a,實際分成 a,b,c等多個塊組合而成。那么這里具體的執行就可能變成:

程序a得到cpu =》cpu加載上下文,開始執行程序a的a小段,然后執行a的b小段,然后再執行a的c小段,最后cpu保存a的上下文。

這里a,b,c的執行是共享了a的上下文,cpu在執行的時候沒有進行上下文切換的。

看到這里是不是對線程共享和線程隔離區有了一個更深次的理解。可以理解為方法區和堆是分配給進程的,也就是線程共享區,而棧和程序計數器則是分配給每個獨立線程的。

在sun公司的hotspot虛擬機中將java虛擬機棧和本地方法棧合二為一了

程序計數器(program counter register)

程序計數器(program counter register)是一塊較小的內存空間,它可以看成是當前線程所執行字節碼的行號指示器。在計算機中,其實程序計數器就是一個寄存器,依據不同計算機細節的差異,它可以存放當前正在被執行的指令,也可以放下一個被執行的指令。

在虛擬機的概念模型中,字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令的。

由于java虛擬機的多線程是通過線程輪詢切換并分配處理器執行時間的方式來實現的,在任何一個確定的時候,一個處理器都只會執行一條線程中的指令,因此為了線程切換之后能過恢復到正確的執行位置,每條線程都需要擁有一個獨立的程序計數器,各條線程之間的計數器互不影響,獨立存儲,所以程序計數器是線程私有的內存,也就是它屬于線程隔離區的。

如果線程執行的是一個java方法,這個計數器記錄的就是正在執行的虛擬機字節碼指令地址;如果正在執行的是native方法,那么這個計數器的值就是(undefined)。

此內存區域是唯一一個在java虛擬機規范中沒有規定任何outofmemoryerror情況的區域。

java虛擬機棧

java虛擬機棧(java virtual machine stack)也是線程私有的,即他的生命周期和線程相同。

在java中,jvm中的棧記錄了線程的方法調用,每個線程擁有一個棧,在某個線程的運行過程中,如果有新的方法調用,那么該線程對應的棧就會增加一個存儲單元,即棧針(stack frame)。

虛擬機棧描述的是java方法執行的內存模型:每個方法在執行時都會創建一個棧針(stack frame)用于存儲局部變量表、操作數棧、動態連接、方法出口等信息。每一個方法從調用至完成的過程,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。

當被調用方法運行結束時,該方法對應的幀將被刪除,參數和局部變量所占據的空間也隨之釋放。線程回到原方法,繼續執行。當所有的棧都清空時,程序也隨之運行結束。

我們經常說的棧內存其實就是現在講的虛擬機棧,或者說是虛擬機棧中局部變量表部分。

局部變量表存放了編譯器可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型,它不等同于對象本身,可能是指向對象起始位置的引用指針,也可能是指向一個代表對象的句柄或其他與此對象相關的位置,引用所指向的對象保存在堆中(引用可能為null,即不指向任何對象))和returnaddress類型(指向了一條字節碼指令的地址)。

其中64位長度的long和double類型的數據會占用2個局部變量空間(slot),其余數據類型只占用1個。局部變量表所需要的內存空間在編譯時期完成分配。當進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改變局部變量表的大小。

異常有兩種

1,線程請求的棧深度大于虛擬機所允許的深度將拋出stackoverflowerror異常 (遞歸調用)

2,如果虛擬機可以動態擴展,如果擴展時已經無法申請到足夠的內存就會拋出outofmemeoryerror異常。

?
1
2
3
4
5
list list=new arraylist();
  for(;;){
   int[] tmp=new int[1000000];
   list.add(tmp);
  }

本地方法棧

本地方法棧(native method stack)與虛擬機棧所發揮的作用是非常相似的。他們之間的區別就是java虛擬機棧是位虛擬機執行java方法(也就是字節碼)服務,而本地方法棧為位虛擬機使用到的native方法服務。

其實虛擬機規范中對本地方發棧中方法所使用的語言、使用方式以及數據結構都沒有強制規定,因此具體的虛擬機可以自由地實現它。甚至在有的虛擬機(如sun hotspot虛擬機)直接就把本地方法棧和虛擬機棧合二為一。與虛擬機棧一樣,本地方法棧區域也會拋出stackoverflowerror和outofmemory異常。

java堆

對于大多數應用來說,java堆(java heap)是java虛擬機管理的內存中最大的一塊。java堆是被所有線程共享的一塊數據區域,在虛擬機啟動時創建,這一內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存。但是隨著jit編譯器的發展與逃逸分析技術逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙的變化發生,所有的對象都分配在堆上也逐漸變得不是那么“絕對”。

堆中可細分為新生代和老年代,在細分可以分為eden空間、form survivor空間、to survivor空間。

java堆是垃圾收集器管理的主要區域,因此很多時候也被稱為“gc堆”。

根據java虛擬機規范規定,java堆可以處于物理上不連續的內存中,即只要邏輯上是連續的即可,就像我們的磁盤空間一樣。在實現時,可以固定大小也是可擴展的。主流的虛擬機都是按照可擴展來實現的(通過-xmx和-xms來控制)。如果在堆中沒有內存可分配,并且堆也無法繼續擴展時,將會拋出outofmemorterror異常。

java的普通對象存活在堆中,與棧不同,堆的空間不會隨著方法調用結束而清空。因此,在某個方法中創建的對象,可以在方法調用結束之后,繼續存在堆中。這帶來的一個問題是,如果我們不斷的創建新的對象,內存控件將會最終消耗殆盡。

方法區

方法區(method area)與java堆一樣,是各個線程共享的內存區域,它用于存儲已經被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯之后的代碼等數據。雖然java虛擬機將其描述為堆的一個邏輯部分,但它卻有一個別名叫做non-heap(非堆)。目的是與java堆區分開來。(以前很多人把方法區稱為永久代,現在jdk1.8中已經用元數據區域取代了永久代)。

運行時常量池

運行時常量池(runtime constant pool)是方法區的一部分。class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息就是常量池。用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入到方法區的運行時常量池中存放。并非預置入class文件中常量池的內容才進入方法運行時常量池,運行期間也可能將新的常量放入池中,這種特性被開發人員利用得比較多的便是string類的intern()方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class test
{
 public static void main(string[] args)
 {
  string s1="hello china";//字節碼常量
  string s2="hello china";
  string s3=new string("hello china");
 
  system.out.println(s1 == s2);
  system.out.println(s1 == s3);
  system.out.println(s1 == s3.intern());//運行時常量 intern 是個native方法
 }
}

java虛擬機深入學習之內存管理機制

當方法區無法滿足內存分配需求時,拋出outofmemoryerror

注:jdk8之前,方法區由永久代實現,主要存放類的信息、常量池、方法數據、方法代碼等;jdk8之后,取消了永久代,提出了元空間,并且常量池、靜態成員變量等遷移到了堆中;元空間不在虛擬機內存中,而是放在本地內存中。

直接內存

由于直接內存(direct memory)并不是java虛擬機運行時數據區的一部分,也不是java虛擬機規范中定義的內存區域,但是這部分也被頻繁使用,而且也可能導致內存溢出異常出現,所以也放到這一部分進行簡介。

先讓,本機直接內存的分配不會受到java堆大小的限制,但是肯定還是會受到本機總內存大小以及處理器尋址空間的限制。管理員在配置虛擬機參數時,會根據實際內存設置-xmx等參數信息,但經常會忽略直接內存,使得各個內存區域總和大于物理內存限制(包含物理的和操作系統級的限制),從而導致動態擴展時出現outofmemoryerror異常。

jdk1.4加入了nio,引入一種基于通道與緩沖區的i/o方式,它可以使用native函數庫直接分配堆外內存,然后通過一個存儲在java堆中的directbytebuffer對象作為這塊內存的引用進行操作。因此避免了在java堆和native堆中來回復制數據,提高了性能。 

?
1
object obj = new object();

object obj將會反映到虛擬機棧中(reference類型)

new object()將會反映到java堆中

此類的對象類型、父類、實現的接口、方法等信息數據,將反映到方法區中

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://www.cnblogs.com/blueskyli/p/8630934.html

延伸 · 閱讀

精彩推薦
  • Java教程java編程中流對象選取規律詳解

    java編程中流對象選取規律詳解

    下面小編就為大家帶來一篇java編程 中流對象選取規律詳解。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧 ...

    java教程網3702020-07-25
  • Java教程Java中集合和數組的排序方式小結

    Java中集合和數組的排序方式小結

    這篇文章主要介紹了Java中集合和數組的排序方式小結,本文講解了對數字數組、字符數組排序以及集合序列的排序,需要的朋友可以參考下 ...

    junjie4872019-12-08
  • Java教程java使用命令行打包JAR

    java使用命令行打包JAR

    如何把寫好的Java程序打包為jar文件呢?下面說的就是java使用命令行打包JAR的方法 ...

    java技術網6992019-10-20
  • Java教程RateLimiter 源碼分析

    RateLimiter 源碼分析

    本文主要對ratelimiter的常用方法以及源碼進行了分析解讀,具有一定參考價值,需要的朋友可以了解下。...

    foolishAndStupid9532021-01-12
  • Java教程Java中ArrayList類的源碼解析

    Java中ArrayList類的源碼解析

    本文主要介紹了Java中ArrayList類的源碼解析,具有很好的參考價值。下面跟著小編一起來看下吧 ...

    朝向遠方5152020-08-27
  • Java教程spring MVC中接口參數解析的過程詳解

    spring MVC中接口參數解析的過程詳解

    這篇文章主要給大家介紹了關于spring MVC中接口參數解析的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring mvc具有一定的參考學習...

    007tangtao5222021-05-13
  • Java教程java實現微信企業付款到個人功能

    java實現微信企業付款到個人功能

    這篇文章主要為大家詳細介紹了java實現微信企業付款到個人功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    藍色格子ren6582021-06-02
  • Java教程java編程中字節流轉換成字符流的實現方法

    java編程中字節流轉換成字符流的實現方法

    下面小編就為大家帶來一篇java編程中字節流轉換成字符流的實現方法。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看...

    jingxian4392020-07-26
主站蜘蛛池模板: 99ri在线精品视频在线播放 | 希岛爱理作品在线观看 | 国产欧美va欧美va香蕉在线观 | 国产片自拍 | 九九免费高清在线观看视频 | 欧美久久一区二区三区 | 2021最新国产成人精品免费 | 好紧好爽再叫浪一点点潘金莲 | 亚洲精品综合 | 亚洲国产婷婷俺也色综合 | xxxx性欧美极品另类 | 国产xxxxxx久色视频在 | 好深快点再快点好爽视频 | 特黄特黄aaaa级毛片免费看 | 99re7在线精品免费视频 | 亚洲黄色大片 | 亚洲免费视频播放 | 成人在线观看一区 | 91国语自产拍在线观看 | 欧美日韩一区二区三区在线视频 | 香港论理午夜电影网 | 亚洲AV永久无码精品老司机蜜桃 | 2012年免费中文视频 | 日b视频免费看 | 国产精品二区高清在线 | 免费看日产一区二区三区 | 日本一道高清不卡免费 | 好大好硬好深好爽想要之黄蓉 | 青青色在线 | 日韩一区二区三区四区区区 | 国内精品99 | 精品手机在线视频 | 男人添女人 | 男女被爆动漫羞羞动漫 | 欧美破苞合集 magnet | 精选国产AV精选一区二区三区 | 射逼网站| 高清国语自产拍免费视频国产 | 亚洲四虎影院 | 性生大片免费看 | 欧美人与禽杂交大片 |