亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java虛擬機解析篇之---內存模型

2019-11-06 06:14:31
字體:
來源:轉載
供稿:網友

今天閑來無事來,看一下java中的內存模型和垃圾回收機制的原理,關于這個方面的知識,網上已經有很多現成的資料可以供我們參考,但是知識還是比較雜的,在這部分知識點中有一本書不得不推薦:《深入理解Java虛擬機》,現在已經是第二版了。這本書就從頭開始詳細介紹了Java整個虛擬機的模型以及Java的類文件結構,加載機制等。這里大部分的知識點都是可以在這本書中找到的,當然我是主要還是借鑒這本書中的很多內容的。下面就不多說了,進入主題吧。

首先來看一下Java中的內存模型圖:

第一、程序計數器(PC)

程序計數器(PRogram Counter Register)是一塊較小的內存空間,它可以看做當前線程所執行的字節碼的行號指示器,字節碼解釋器工作時就是通過改變這個計數器的值來取下一條需要執行的字節碼指令,分支、跳轉、循環、異常處理、線程恢復等基礎功能都需要這個計數器來完成

注:程序計數器是線程私有的,每條線程都會有一個獨立的程序計數器

第二、Java棧(虛擬機棧)

Java棧就是Java中的方法執行的內存模型,每個方法在執行的同時都會創建一個棧幀(關于棧幀后面介紹),這個棧幀用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息,每個方法從調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。

注:Java棧也是線程私有的。

異常可能性:對于棧有兩種異常情況:如果線程請求的棧深度大于棧所允許的深度,將拋出StackOverflowError異常,如果虛擬機棧可以動態拓展,在拓展的時無法申請到足夠的內存,將會拋出OutOfMemoryError異常

棧幀的概念:

棧幀用于支持虛擬機進行方法調用和執行的數據結構。

1) 局部變量表

局部變量表(Local Variable Table)是一組 變量值存儲空間,用于存放 方法參數和方法內部定義的局部變量.局部變量表的容量以變量槽(Variable Slot,下稱Slot)為最小單位. 一個Slot可以存放一個32位以內的數據類型,Java中占用32位以內的數據類型有boolean、byte、char、short、int、float、reference[3]和returnAddress 8種類型,對于 64位的數據類型,虛擬機會以高位對齊的方式為其 分配兩個連續的Slot空間(long double).

2) 操作數棧

操作數棧(Operand Stack)也常稱為操作棧,它是一個后入先出(Last In First Out,LIFO)棧,當一個方法剛剛執行的時候,這個方法的操作數棧是空的,在方法的執行過程中,會有各種字節碼指令往操作數棧中寫入和提取內容,也就是出棧/入棧操作,例如,在做算術運算的時候通過操作數棧來進行的,又或者在調用其他方法的時候是通過操作數棧來進行參數傳遞的。

舉個例子:整數假發的字節碼指令iadd在運行的時候操作數棧中最接近棧頂的兩個元素已經存入了兩個int類型的數值,當執行這個指令時,會將這兩個int值出棧并相加,然后將相加的結果入棧。

3) 方法返回地址

一個方法開始執行后,只有 兩種方式可以退出這個方法。第一種方式是執行引擎遇到任意一個方法返回的字節碼指令,這時候可能會有返回值傳遞給上層的方法調用者(調用當前方法的方法稱為調用者),是否有返回值和返回值的類型將根據遇到何種方法返回指令來決定,這種退出方法的方式稱為 正常完成出口(Normal Method Invocation Completion)。另外一種退出方式是,在方法執行過程中 遇到了異常,并且這個異常沒有在方法體內得到處理,無論是Java虛擬機內部產生的異常,還是代碼中使用athrow字節碼指令產生的異常,只要在本方法的異常表中沒有搜索到匹配的異常處理器,就會導致方法退出,這種退出方法的方式稱為 異常完成出口(Abrupt Method Invocation Completion)。 一個方法使用異常完成出口的方式退出,是不會給它的上層調用者產生任何返回值的  

4) 附加信息

虛擬機規范允許具體的虛擬機實現增加一些規范里沒有描述的信息到棧幀之中,例如與調試相關的信息,這部分信息完全取決于具體的虛擬機實現,這里不再詳述。在實際開發中,一般會把動態連接、方法返回地址與其他附加信息全部歸為一類,稱為棧幀信息。

第三、本地方法棧

本地方法棧與Java棧所發揮的作用是非常相似的,它們之間的區別不過是Java棧執行Java方法,本地方法棧執行的是本地方法。

注:本地方法棧也是線程私有的

異??赡苄裕汉蚃ava棧一樣,可能拋出StackOverflowError和OutOfMemeryError異常

第四、Java堆

對于大多數應用來說,Java堆是Java虛擬機所管理的內存中最大的一塊,在虛擬機啟動時創建。此內存區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存,當然我們后面說到的垃圾回收器的內容的時候,其實Java堆就是垃圾回收器管理的主要區域。

注:堆是線程共享的

異??赡苄裕喝绻阎袥]有內存完成實例分配,并且堆也無法再拓展時,將會拋出OutOfMemeryError異常

第五、方法區

方法區它用于存儲已被虛擬機加載的類信息、常量、靜態常量、即時編譯器編譯后的代碼等數據。

注:方法區和堆一樣是線程共享的

異??赡苄裕寒敺椒▍^無法滿足內存分配需求時,將拋出OutOfMemeryError異常

1)運行時常量池

運行時常量池是方法區的一部分,Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用于存放編譯器生成的各種字面量和符號引用,這部分內容將在類加載器后進入方法區的運行時異常常量池存放。

上面就介紹了Java的內存的幾個模塊的相關概念,其實我們需要知道這些知識,最主要的目的是不要在項目中寫那些OOM的代碼,因為我們如果知道了內存模型之后,即使代碼中出現了OOM的問題,我們可以定位到哪里出了問題。

下面也來看一下上面說到的幾個內存模塊導致的內存溢出異常問題:

(這個也是面試的時候經常會被問到:比如叫你寫一段讓堆內存溢出的代碼,或者是問你如果如果修改堆大小)

第一、堆溢出

 

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片public class HeapOOM {            static class OOMObject{}        /**      * @param args      */      public static void main(String[] args) {          List<OOMObject> list = new ArrayList<OOMObject>();                    while(true){              list.add(new OOMObject());          }      }    }  

我們上面看到堆主要是存放對象的,所以我們如果想讓堆出現OOM的話,可以開一個死循環,然后產生新的對象就可以了。然后在將堆的大小調小點。

加上JVM參數

-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,

就能很快報出OOM:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

第二、棧溢出

 

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片package com.cutesource;    public class StackOOM {        /**      * @param args      */            private int stackLength = 1;            public void stackLeak(){          stackLength++;          stackLeak();      }            public static void main(String[] args) throws Throwable{          // TODO Auto-generated method stub          StackOOM oom = new StackOOM();          try{              oom.stackLeak();          }catch(Throwable err){              System.out.println("Stack length:" + oom.stackLength);              throw err;          }                }    }  

我們知道棧中存放的方法執行的過程中需要的空間,所以我們可以下一個循環遞歸,這樣方法棧就會出現OOM的異常了。

設置JVM參數:-Xss128k,報出異常:

Exception in thread "main" java.lang.StackOverflowError

打印出Stack length:1007,這里可以看出,在我的機器上128k的棧容量能承載深度為1007的方法調用。當然報這樣的錯很少見,一般只會出現無限循環的遞歸中,另外,線程太多也會占滿棧區域:

 

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片package com.cutesource;    public class StackOOM {        /**      * @param args      */            private int stackLength = 1;            private void dontStop(){          while(true){              try{Thread.sleep(1000);}catch(Exception err){}          }      }            public void stackLeakByThread(){          while(true){              Thread t = new Thread(new Runnable(){                    @Override                  public void run() {                      // TODO Auto-generated method stub                      dontStop();                  }                                });              t.start();              stackLength++;          }      }            public static void main(String[] args) throws Throwable{          // TODO Auto-generated method stub          StackOOM oom = new StackOOM();          try{              oom.stackLeakByThread();          }catch(Throwable err){              System.out.println("Stack length:" + oom.stackLength);              throw err;          }                }    }  

這個棧的溢出,就是我們上面說到棧的時候的兩種異常情況。

報出異常:Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread

第三、方法區溢出

 

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片public class MethodAreaOOM {            static class OOMOjbect{}        /**      * @param args      */      public static void main(String[] args) {          // TODO Auto-generated method stub          while(true){              Enhancer eh = new Enhancer();              eh.setSuperclass(OOMOjbect.class);              eh.setUseCache(false);              eh.setCallback(new MethodInterceptor(){                    @Override                  public Object intercept(Object arg0, Method arg1,                          Object[] arg2, MethodProxy arg3) throws Throwable {                      // TODO Auto-generated method stub                      return arg3.invokeSuper(arg0, arg2);                  }                                });              eh.create();          }      }    }  

我們知道方法區是存放一些類的信息等,所以我們可以使用類加載無限循環加載class,這樣就會出現方法區的OOM異常。

手動將棧的大小調小點

加上JVM參數:-XX:PermSize=10M -XX:MaxPermSize=10M,運行后會報如下異常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

第四、常量池溢出

 

[java] view plain copy 在CODE上查看代碼片派生到我的代碼片public class ConstantOOM {        /**      * @param args      */      public static void main(String[] args) {          // TODO Auto-generated method stub          List<String> list = new ArrayList<String>();          int i=0;          while(true){              list.add(String.valueOf(i++).intern());          }      }    }  

我們知道常量池中存放的是運行過程中的常量,同時我們知道String類型的intern方法是將字符串的值放到常量池中的。所以上面弄可以開一個死循環將字符串的值都放到常量池中,這樣常量池就會出現OOM異常了。因為常量池本身就是方法區的一部分,所以我們也可以手動的調節一下棧的大小。

總結:上面只是從宏觀的角度介紹了一下內存模型,具體關于內存中每個區域的詳細信息,可以閱讀開頭說到的那本很不錯的書籍。當然我們在學習Java的時候可以分為四大模塊:Java的Api、Java虛擬機(內存模型和垃圾回收器)、Java的Class文件、設計模式,關于Api的知識我們在工作的過程中用到的比較多,而且這部分內容完全是靠使用度,你用多了,api你自然就知道了。Java虛擬機和Java的Class文件的相關知識在工作中可能不一定能用到,但是這方面的知識能夠讓你更了解Java的整個體系結構。至于設計模式這個就是修煉的過程,也是最難的過程。得慢慢的體會其的強大之處。

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久精品国产亚洲精品| 成人免费黄色网| 国产一区欧美二区三区| 国产精品视频男人的天堂| 国产精品久久久久久久久免费| 免费97视频在线精品国自产拍| 亚洲最大福利网站| 欧美性猛交xxxx富婆弯腰| 国产97在线播放| 97久久精品视频| 亚洲免费中文字幕| 精品亚洲一区二区三区在线观看| 操人视频在线观看欧美| xxx成人少妇69| 亚洲免费人成在线视频观看| 日韩成人中文电影| 国产亚洲精品美女久久久| 日韩视频免费在线| 伊人久久免费视频| 欧美放荡办公室videos4k| 日韩一区二区三区xxxx| 国产精品久久久久久久久粉嫩av| 亚洲精品国产福利| 欧美日韩亚洲高清| 51视频国产精品一区二区| 亚洲国产成人一区| 中文字幕v亚洲ⅴv天堂| 姬川优奈aav一区二区| 亚洲男人的天堂在线播放| 91日本视频在线| 亚洲欧美中文日韩在线v日本| 亚洲人永久免费| 亚洲四色影视在线观看| 91精品综合久久久久久五月天| 亚洲伊人成综合成人网| 福利一区视频在线观看| 国产精品久久久久久av福利软件| 日韩国产在线看| 精品日韩视频在线观看| 国产免费成人av| 亚洲一区免费网站| 青青草原一区二区| 亚洲香蕉成视频在线观看| 日韩免费av在线| 久久久女女女女999久久| 亚洲精品综合久久中文字幕| 一区二区三区四区在线观看视频| 久久这里只有精品视频首页| 国产成人一区二区三区| 91在线国产电影| 亚洲国产成人在线视频| 色999日韩欧美国产| 成人黄色免费网站在线观看| 欧美激情一区二区三级高清视频| 久久九九亚洲综合| 欧美日韩综合视频网址| 日本久久久久亚洲中字幕| 国产精品欧美一区二区三区奶水| 久久艹在线视频| 亚洲xxxx妇黄裸体| 中文字幕不卡在线视频极品| 国产精品a久久久久久| 成人伊人精品色xxxx视频| 欧美精品成人91久久久久久久| 国产日韩欧美视频| 黑人巨大精品欧美一区二区免费| 亚洲日本欧美中文幕| 亚洲视频axxx| 欧美日韩中文在线观看| 欧美性色19p| 欧美大人香蕉在线| 国产精品香蕉在线观看| 日韩av手机在线观看| 国产有码一区二区| 亚洲精品v天堂中文字幕| 欧美精品激情blacked18| 国产综合在线视频| 国产精品美女免费视频| 亚洲天天在线日亚洲洲精| 精品亚洲一区二区三区在线观看| 久久乐国产精品| 日韩一区二区久久久| 亚洲四色影视在线观看| 久久高清视频免费| 久久综合色88| 成人疯狂猛交xxx| 成人在线免费观看视视频| 久久人人爽人人爽人人片亚洲| 亚洲精品白浆高清久久久久久| 亚洲第一精品夜夜躁人人爽| 亚洲午夜性刺激影院| 欧美日本精品在线| 97色在线播放视频| 久久人91精品久久久久久不卡| 国产一区二区三区三区在线观看| 夜夜嗨av一区二区三区免费区| 国产一区二区在线免费视频| 91精品免费久久久久久久久| 午夜伦理精品一区| 在线观看国产精品91| 精品毛片三在线观看| 久久久视频在线| 国产91精品久久久久久久| 国产专区欧美专区| 欧洲中文字幕国产精品| 久久99国产精品自在自在app| 欧美裸体xxxx| 秋霞成人午夜鲁丝一区二区三区| 亚洲最大福利视频| 国产精品成人av在线| 亚洲综合中文字幕在线观看| 亚洲永久免费观看| 黄色成人av网| 精品国产欧美一区二区五十路| 亚洲精品suv精品一区二区| 日韩精品在线观看一区二区| 91在线看www| 欧美激情手机在线视频| 国内精品久久影院| 欧美性猛交xxxx黑人猛交| 激情久久av一区av二区av三区| 欧美在线视频网| 亚洲无限乱码一二三四麻| 欧美性猛交xxxx黑人| 国产成人精品av| 国产一区二区三区在线看| 欧美激情成人在线视频| 国产精品视频久久久| 成人精品一区二区三区| 久久夜色精品国产| 亚洲欧美激情四射在线日| 国产精品久久久久一区二区| 亚洲成人国产精品| 国产不卡av在线免费观看| 欧美极品第一页| 色综合影院在线| 中文字幕日韩在线播放| 中文字幕欧美视频在线| 国产欧美一区二区三区久久人妖| 91精品美女在线| 精品久久久久久| 亚洲国产成人爱av在线播放| 国产欧美日韩精品丝袜高跟鞋| 国产精品网站入口| 亚洲国产精品嫩草影院久久| 久久免费成人精品视频| 日本精品久久电影| 亚洲free性xxxx护士白浆| 国产69精品久久久久9| 裸体女人亚洲精品一区| 日韩亚洲欧美中文在线| 欧美激情小视频| 97视频在线观看网址| 久久久久国产精品免费网站| 欧美日在线观看| 国产+成+人+亚洲欧洲| 91精品国产高清久久久久久91| 中文字幕少妇一区二区三区| 日本精品视频在线播放| 国产欧美精品日韩| 久久亚洲精品视频| 久久精品视频播放| 久久久免费在线观看| 亚洲xxxxx电影|