jvm_堆栈永久区详细讲解
生活随笔
收集整理的這篇文章主要介紹了
jvm_堆栈永久区详细讲解
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
第一塊是堆,第二塊是垃圾收集器,這就是咱們要講的兩塊堆是JAVA中非常關鍵非常核心的一部分,因為JAVA實例化出來的一些對象,都是存在內存堆空間中的,幾乎所有的對象都放在其中,且JAVA堆完全是由垃圾回收系統自動管理的,不是像C語言要手動寫一個命令GC的那種東西,堆是自動管理的,是通過垃圾回收系統自動化管理的,通過垃圾回收機制,我們會把這個對象自動去清理,不需要像其他語言比如C顯示的是釋放,然后根據垃圾回收機制的不同,注意我的PPT寫了,JAVA堆中可能有不同的結構,總的區域是一定的,最為常見的就是將整個堆分為新生代和老年代這兩個大塊,一大塊就是叫做新生代,一大塊就是叫做老年代,這是面試問的非常多的,JAVA堆知道是怎么劃分的嗎,JAVA新生代存放新生產出來的對象,老年代就存放已經生產很久的對象,新生代就是年齡不大的對象,老年代就是年紀很大的對象,具體它是怎樣劃分的呢,新生代又分成3個區域,分為eden區,s0區,s1區,s0和s1也被稱為from和to區域,他們是兩塊大小相等并且可以互換角色的空間,他們指的是s0和s1區
其實在我們的JAVA中堆就這么一塊空間,稱之為JAVA的heap,它分為兩大塊,整體上分為2大塊,第一大塊叫做新生代,第二大塊叫做老年代,這是最外面最宏觀的一次劃分,然后關于新生代這塊,有分為3塊區域,首先第一塊叫做eden區,為什么叫做eden呢,這個翻譯過來叫做伊甸園,所以我們給他取個名字叫eden,其實我們的JAVA對象剛剛實例化出來的時候,剛new出來的時候,這個對象是放在eden區的,然后經過1次垃圾回收機制,經過1次GC就是、垃圾收集器,就是這個對象看有沒有用了,比如這個代碼寫完以后,只要他經歷過一次GC的話,user對象就會從Eden區域出來,出來不是直接到老年代,它就會到s0和s1區域,或者叫做from和to,s0和s1區域他們兩個是什么概念呢,這兩塊區域是兩塊大小相等,并且是可以相互轉換角色的空間,為什么要這么去設計呢,說明我們JAVA的對象,user經歷過1次GC以后,會到s0或者是s1區,就是這對象可能是到s0區,也可能是s1區,就不可能是這個對象既在s0區也在s1區,說明就在我們這個JAVA中對象要么都存在s0區,要么都存在s1區,就是如果一個對象存在s0區,那s1區就不會有任何對象,如果有對象存在s1區,s0區就沒有任何對象,所以他們就是兩個大小相等,并且可以想換轉換角色的空間,為什么我們的JAVA虛擬機是這么去設置的呢,在老年代里就無所謂了,老年代就是經歷過多少次GC以后比如我們JAVA里面默認是經過15次GC以后,它就會從新生代晉升到老年代,但是我們唯一不理解的就是s0和s1咱們的JAVA虛擬機為什么設計成這種形式,s0和s1這一塊可能不理解,那根據我們剛才所描述的概念.大多數情況下,我們的對象首先分配在eden區,在一次新生代回收之后,也就是垃圾回收之后,如果還存活著,如果程序還用著這個user,那么這個對象就會進入到s0或者s1區,因為不可能兩個都有,每次經歷GC操作的時候,如果我們的對象一直存活,那它的年齡就加1,也就是第一次回收了,發現還被程序使用者,那就加1,第2次GC再加1,一直加到15的時候OK,無論是s0區也好,還是s1區也好,這個對象就會直接扔到老年代這塊,在這里簡單跟大家說一下
垃圾收集算法,其中有一個非常經典的算法,就是復制的算法,其核心就是將內存空間分為兩塊,每次只能使用其中的一塊,在垃圾回收的時候,將正在使用的內存中的存留的對象復制到未被使用的內存塊中去,之后去清除之前正在使用的內存塊中所有的對象,反復去交換兩個內存的角色,完成垃圾收集,你該明白新生代和老年代是一個什么樣的概念了,它就是一個交替呼喚的角色,為什么要這么去設計呢,咱們單獨來分析新生代的s0和s1這兩個區間他們是兩塊大小相等并且可以呼喚角色的空間,我們這邊叫做新生代,其實在我們的JAVA里邊,你寫程序寫了很多代碼,你在應用系統里邊,很多對象就用了一次,或者調用的時候就用了一次,它不可能常駐在我們的內存中的,所以對一用完了就馬上被回收,所以就在新生代的時候,垃圾回收太頻繁了,并且需要垃圾回收的對象也太多了,比如現在我們的程序創建了100個Object,在這100個對象中,可能僅僅百分之1或者百分之2,這是比較常見的,就是100個對象里面只有1個或者2個存活在15次以上,存活15次以上才會存放在老年代,一般的JAVA對象經歷了幾次的GC之后,都會被我們的垃圾回收機制給回收掉,并且在我們的新生代產生對象實在是太頻繁,老年代產生的GC要少于新生代很多很多,因為你的這個對象已經經歷了15次的淘汰了,還沒有被回收,老年代的對象在我們老年代的周期,你的這個JAVA程序或者servlet,tomcat的啟動到關閉的整個生命周期內這個對象始終都在用著,但是絕大部分的對象在新生代生產消亡,分配空間,經歷幾次GC之后就消亡了,我們有n個對象放在s0區,然后我們采用的是復制的算法,比如我們這里有100個對象,有40個對象還,咱們的垃圾回收機制怎么做呢,這40個還存活的對象copy到s1去,剩下就不管了,清空這塊s0區,下次我們就用我們的s1區,下次我們GC的時候,還有20個還存活著,然后再把s1的20個再copy回來,可能就是一個遞歸了,其實就是源源不斷有新的對象產出,然后由老的對象經歷過幾次GC被回收的情況,這個就是一個概念性的問題,為什么要使用復制算法,就是因為新生代太頻繁了,對象的產生和被垃圾回收走太頻繁了,所以我們要有一種復制的算法,然后去清空空間,這兩個角色相互交替的轉換
其實就是一個概念性的問題,其實真正工作的時候用的不是特別的多,復制肯定不會包括eden區,eden區就包括對象,對象經歷過一次GC之后肯定從eden區出來,到咱們的s0或者s1
JAVA棧就是咱們線程的一塊私有空間,每一個線程你去實例創建的時候會有一個Thread,你會發現棧和我們的線程是息息相關的,調用多少次,比如深度什么的,后期咱們看代碼就知道了,棧咱們也分三個部分,局部變量表,操作數棧,幀數據區,這三個東西比較拗口.1. 局部變量表: 用于報錯函數的參數及局部變量2. 操作數棧: 主要保存計算過程的中間結果,代碼寫一個冒泡排序,你寫代碼的時候就有一個臨時轉換的角色,臨時變量的轉換角色3. 幀數據區: 也是用于處理一些異常,函數的返回結果或者出現異常,必須有一個異常處理表,其實局部變量表和幀數據區差不多,一個是函數報錯參數的存儲,還有一個是返回結果報錯存儲的,涉及到了一些常量的指針,因為很少有人讀一下JAVA虛擬機源碼,因為肯定是用C寫的,只要存一些打印的信息就行了,然后咱們臨時變量的存儲呢,是存在操作數棧這個東西里,那咱們最簡單明了的一句話,棧存的都是一些臨時變量,方法中肯定會寫一行一行的代碼,然后變量相互的去轉換,具體內部可能是通過這3分區域去進行維護的,你可以不用了解的非常詳細,這塊你有興趣你可以去查查資料,一般不會問你棧太核心的,如果問了你可以反問他,你可以說記得棧里面分了局部變量表,操作數棧,幀數據區這三個部分,那我可能知道操作數棧寫代碼臨時中間變量的轉換,局部變量表和幀數據區是打印一些方法的入口,出口的一些異常,了解到這里就行了
JAVA方法區和堆一樣,方法區是一塊所有線程共享的內存區域,靜態的,類的字段,方法,方法區的大小可以決定系統可以保存多少個類,如果系統定義的類太多,就會導致方法區溢出,你可能寫了一個非常大的一塊代碼,你做了一個非常復雜的垂直化的系統,里面400、500個類,然后你給Tomcat的方法區幾百個M,Tomcat就會報方法區的內存溢出,它會有這個提示,它就是永久區.虛擬機同樣也會提示這種錯誤,現在我們其實不用面對這種問題,因為我們現在都是很多面多微服務,都是面向分布式的服務,一個服務不可能放一個非常復雜的業務系統,所以這個異常我們可以忽略,方法區就和我們創建多少個類直接關聯.
?
總結
以上是生活随笔為你收集整理的jvm_堆栈永久区详细讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jvm_虚拟机组成部分概述
- 下一篇: jvm_虚拟机参数讲解(一)