偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

JVM內(nèi)存模型總結(jié)和上手實(shí)踐,親測(cè)學(xué)完沒(méi)脫發(fā)!

存儲(chǔ) 存儲(chǔ)軟件 虛擬化
最近看到一篇文章,30歲有多難。文中的一些主人公好像在學(xué)業(yè)、工作、生活、愛(ài)情等方面都過(guò)的都不如意。要不是錯(cuò)過(guò)這,要不是走錯(cuò)那??偨Y(jié)來(lái)看,就像是很倒霉的一群倒霉蛋兒在跟生活對(duì)干!

 [[374276]]

本文轉(zhuǎn)載自微信公眾號(hào)「bugstack蟲(chóng)洞?!?,作者小傅哥。轉(zhuǎn)載本文請(qǐng)聯(lián)系bugstack蟲(chóng)洞棧公眾號(hào)。  

目錄

  • 一、前言
  • 二、面試題
  • 三、 JDK1.6、JDK1.7、JDK1.8 內(nèi)存模型演變
  • 四、內(nèi)存模型各區(qū)域介紹
    • 1. 程序計(jì)數(shù)器
    • 2. Java虛擬機(jī)棧
    • 3. 本地方法棧
    • 4. 堆和元空間
    • 5. 常量池
  • 五、手?jǐn)]虛擬機(jī)(內(nèi)存模型)
    • 1. 工程結(jié)構(gòu)
    • 2. 重點(diǎn)代碼
  • 六、jconsole監(jiān)測(cè)元空間溢出
    • 1. 找段持續(xù)創(chuàng)建大對(duì)象的代碼
    • 2. 調(diào)整元空間大小
    • 3. 設(shè)置監(jiān)控參數(shù)
    • 4. 測(cè)試運(yùn)行
  • 七、總結(jié)
  • 八、系列推薦

一、前言

看了一篇文章30歲有多難!

每篇文章的開(kāi)篇總喜歡寫(xiě)一些,從個(gè)人視角看這個(gè)世界的感悟。

最近看到一篇文章,30歲有多難。文中的一些主人公好像在學(xué)業(yè)、工作、生活、愛(ài)情等方面都過(guò)的都不如意。要不是錯(cuò)過(guò)這,要不是走錯(cuò)那??偨Y(jié)來(lái)看,就像是很倒霉的一群倒霉蛋兒在跟生活對(duì)干!

但其實(shí)每個(gè)人可能都遇到過(guò)生活中最難的時(shí)候,或早或晚。就像我剛畢業(yè)不久時(shí)一連串遇到;冬天里丟過(guò)第一部手機(jī)、修一個(gè)進(jìn)了水的電腦、租的房子第一次被騙,一連串下來(lái)頭一次要趕在工資沒(méi)發(fā)的時(shí)候,選擇少吃早飯還是午飯,看看能扛過(guò)去那頓。

哈哈哈哈哈,現(xiàn)在想想還挺有意思的,不過(guò)這些亂遭的事很多是自己的意識(shí)和能力不足時(shí)做出的錯(cuò)誤選擇而導(dǎo)致的。

人那,想開(kāi)車就要考駕照,想走遠(yuǎn)就要有能力。多提升認(rèn)知,多拓寬眼界!生活的意義就是不斷的更新自己!

二、面試題

謝飛機(jī),小記!,冬風(fēng)吹、戰(zhàn)鼓擂。被窩里,誰(shuí)怕誰(shuí)。

「謝飛機(jī)」:歪?大哥,你在嗎?

「面試官」:咋了,大周末的,這么早打電話!?

「謝飛機(jī)」:我夢(mèng)見(jiàn),我去谷歌寫(xiě)JVM了,給你們公司用,之后蹦了,讓我起來(lái)改bug!

「面試官」:啊!?啊,那我問(wèn)你,JDK 1.8 與 JDK 1.7 在運(yùn)行時(shí)數(shù)據(jù)區(qū)的設(shè)計(jì)上,你都怎么做的優(yōu)化策略的?

「謝飛機(jī)」:我沒(méi)寫(xiě)這,我不知道!

「面試官」:擦。。。

三、 JDK1.6、JDK1.7、JDK1.8 內(nèi)存模型演變

圖 25-1 JDK1.6、JDK1.7、JDK1.8,內(nèi)存模型演變

如圖 25-1 是 JDK 1.6、1.7、1.8 的內(nèi)存模型演變過(guò)程,其實(shí)這個(gè)內(nèi)存模型就是 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)依照J(rèn)VM虛擬機(jī)規(guī)范的具體實(shí)現(xiàn)過(guò)程。

在圖 25-1 中各個(gè)版本的迭代都是為了更好的適應(yīng)CPU性能提升,最大限度提升的JVM運(yùn)行效率。這些版本的JVM內(nèi)存模型主要有以下差異:

  • JDK 1.6:有永久代,靜態(tài)變量存放在永久代上。
  • JDK 1.7:有永久代,但已經(jīng)把字符串常量池、靜態(tài)變量,存放在堆上。逐漸的減少永久代的使用。
  • JDK 1.8:無(wú)永久代,運(yùn)行時(shí)常量池、類常量池,都保存在元數(shù)據(jù)區(qū),也就是常說(shuō)的元空間。但字符串常量池仍然存放在堆上。

四、內(nèi)存模型各區(qū)域介紹

1. 程序計(jì)數(shù)器

較小的內(nèi)存空間、線程私有,記錄當(dāng)前線程所執(zhí)行的字節(jié)碼行號(hào)。

如果執(zhí)行 Java 方法,計(jì)數(shù)器記錄虛擬機(jī)字節(jié)碼當(dāng)前指令的地址,本地方法則為空。

這一塊區(qū)域沒(méi)有任何 OutOfMemoryError 定義。

「以上」,就是關(guān)于程序計(jì)數(shù)器的定義,如果這樣看沒(méi)有感覺(jué),我們舉一個(gè)例子。

定義一段 Java 方法的代碼,這段代碼是計(jì)算圓形的周長(zhǎng)。

  1. public static float circumference(float r){ 
  2.         float pi = 3.14f; 
  3.         float area = 2 * pi * r; 
  4.         return area; 

接下來(lái),如圖 25-2 是這段代碼的在虛擬機(jī)中的執(zhí)行過(guò)程,左側(cè)是它的程序計(jì)數(shù)器對(duì)應(yīng)的行號(hào)。

圖 25-2 程序計(jì)數(shù)器

這些行號(hào)每一個(gè)都會(huì)對(duì)應(yīng)一條需要執(zhí)行的字節(jié)碼指令,是壓棧還是彈出或是執(zhí)行計(jì)算。

之所以說(shuō)是線程私有的,因?yàn)槿绻皇撬接械模敲凑麄€(gè)計(jì)算過(guò)程最終的結(jié)果也將錯(cuò)誤。

2. Java虛擬機(jī)棧

  • 每一個(gè)方法在執(zhí)行的同時(shí),都會(huì)創(chuàng)建出一個(gè)棧幀,用于存放局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口、線程等信息。
  • 方法從調(diào)用到執(zhí)行完成,都對(duì)應(yīng)著棧幀從虛擬機(jī)中入棧和出棧的過(guò)程。
  • 最終,棧幀會(huì)隨著方法的創(chuàng)建到結(jié)束而銷毀。

可能這么只從定義看上去仍然沒(méi)有什么感覺(jué),我們?cè)僬乙粋€(gè)例子。

這是一個(gè)關(guān)于斐波那契數(shù)列(Fibonacci sequence)求值的例子,我們通過(guò)斐波那契數(shù)列在虛擬機(jī)中的執(zhí)行過(guò)程,來(lái)體會(huì)Java虛擬機(jī)棧的用途。

斐波那契數(shù)列(Fibonacci sequence),又稱黃金分割數(shù)列、因數(shù)學(xué)家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數(shù)列”,指的是這樣一個(gè)數(shù)列:1、1、2、3、5、8、13、21、34、……在數(shù)學(xué)上,斐波納契數(shù)列以如下被以遞推的方法定義:F(1)=1,F(xiàn)(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)在現(xiàn)代物理、準(zhǔn)晶體結(jié)構(gòu)、化學(xué)等領(lǐng)域,斐波納契數(shù)列都有直接的應(yīng)用,為此,美國(guó)數(shù)學(xué)會(huì)從1963年起出版了以《斐波納契數(shù)列季刊》為名的一份數(shù)學(xué)雜志,用于專門(mén)刊載這方面的研究成果。

圖 25-3 斐波那契數(shù)列在虛擬機(jī)棧中的執(zhí)行過(guò)程

整個(gè)這段流程,就是方法的調(diào)用和返回。在調(diào)用過(guò)程申請(qǐng)了操作數(shù)棧的深度和局部變量的大小。

以及相應(yīng)的信息從各個(gè)區(qū)域獲取并操作,其實(shí)也就是入棧和出棧的過(guò)程。

3. 本地方法棧

本地方法棧與Java虛擬機(jī)棧作用類似,唯一不同的就是本地方法棧執(zhí)行的是Native方法,而虛擬機(jī)棧是為JVM執(zhí)行Java方法服務(wù)的。

另外,與 Java 虛擬機(jī)棧一樣,本地方法棧也會(huì)拋出 StackOverflowError 和 OutOfMemoryError 異常。

JDK1.8 HotSpot虛擬機(jī)直接就把本地方法棧和虛擬機(jī)棧合二為一。

關(guān)于本地方法棧在以上的例子已經(jīng)涉及了這部分內(nèi)容,這里就不在贅述了。

4. 堆和元空間

圖 25-4 Java 堆區(qū)域劃分

  • JDK 1.8 JVM 的內(nèi)存結(jié)構(gòu)主要由三大塊組成:堆內(nèi)存、元空間和棧,Java 堆是內(nèi)存空間占據(jù)最大的一塊區(qū)域。
  • Java 堆,由年輕代和年老代組成,分別占據(jù)1/3和2/3。
  • 而年輕代又分為三部分,「Eden」、「From Survivor」、「To Survivor」,占據(jù)比例為8:1:1,可調(diào)。
  • 另外這里我們特意畫(huà)出了元空間,也就是直接內(nèi)存區(qū)域。在 JDK 1.8 之后就不在堆上分配方法區(qū)了。
  • 「元空間」從虛擬機(jī)Java堆中轉(zhuǎn)移到本地內(nèi)存,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存的限制,說(shuō)白了也就是以后不會(huì)因?yàn)橛谰么臻g不夠而拋出OOM異常出現(xiàn)了。jdk1.8以前版本的 class和JAR包數(shù)據(jù)存儲(chǔ)在 PermGen下面 ,PermGen 大小是固定的,而且項(xiàng)目之間無(wú)法共用,公有的 class,所以比較容易出現(xiàn)OOM異常。
  • 升級(jí) JDK 1.8后,元空間配置參數(shù),-XX:MetaspaceSize=512M XX:MaxMetaspaceSize=1024M。教你個(gè)小技巧通過(guò)jps、jinfo查看元空間,如下:

通過(guò)命令查看元空間

通過(guò)jinfo查看默認(rèn)MetaspaceSize大小(約20M),MaxMetaspaceSize比較大。

「其他:關(guān)于 JDK1.8 元空間的介紹:」 Move part of the contents of the permanent generation in Hotspot to the Java heap and the remainder to native memory. http://openjdk.java.net/jeps/122

5. 常量池

從 JDK 1.7開(kāi)始把常量池從永久代中剝離,直到 JDK1.8 去掉了永久代。而字符串常量池一直放在堆空間,用于存儲(chǔ)字符串對(duì)象,或是字符串對(duì)象的引用。

五、手?jǐn)]虛擬機(jī)(內(nèi)存模型)

其實(shí)以上的內(nèi)容,已經(jīng)完整的介紹了JVM虛擬機(jī)的內(nèi)存模型,也就是運(yùn)行時(shí)數(shù)據(jù)區(qū)的結(jié)構(gòu)。但是這東西看完可能就忘記了,因?yàn)槿鄙僖粋€(gè)可親手操作的代碼。

「所以」,這里我給大家用Java代碼寫(xiě)一段關(guān)于數(shù)據(jù)槽、棧幀、局部變量、虛擬機(jī)棧以及堆的代碼結(jié)構(gòu),讓大家更好的加深對(duì)虛擬機(jī)內(nèi)存模型的印象。

1. 工程結(jié)構(gòu)

運(yùn)行時(shí)數(shù)據(jù)區(qū)

  1. 運(yùn)行時(shí)數(shù)據(jù)區(qū) 
  2. ├── heap 
  3. │   ├── constantpool 
  4. │   ├── methodarea 
  5. │   │   ├── Class.java 
  6. │   │   ├── ClassMember.java 
  7. │   │   ├── Field.java 
  8. │   │   ├── Method.java 
  9. │   │   ├── MethodDescriptor.java 
  10. │   │   ├── MethodDescriptorParser.java 
  11. │   │   ├── MethodLookup.java 
  12. │   │   ├── Object.java 
  13. │   │   ├── Slots.java 
  14. │   │   └── StringPool.java 
  15. │   └── ClassLoader.java 
  16. ├── Frame.java 
  17. ├── JvmStack.java 
  18. ├── LocalVars.java 
  19. ├── OperandStack.java 
  20. ├── Slot.java 
  21. └── Thread.java 

以上這部分就是使用Java實(shí)現(xiàn)的部分JVM虛擬機(jī)功能,這部分主要包括如下內(nèi)容:

  • Frame,棧幀
  • JvmStack,虛擬機(jī)棧
  • LocalVars,局部變量
  • OperandStack,操作數(shù)棧
  • Slot,數(shù)據(jù)槽
  • Thread,線程
  • heap,堆,里面包括常量池和方法區(qū)

2. 重點(diǎn)代碼

「操作數(shù)棧 OperandStack」

  1. public class OperandStack { 
  2.  
  3.     private int size = 0; 
  4.     private Slot[] slots; 
  5.  
  6.     public OperandStack(int maxStack) { 
  7.         if (maxStack > 0) { 
  8.             slots = new Slot[maxStack]; 
  9.             for (int i = 0; i < maxStack; i++) { 
  10.                 slots[i] = new Slot(); 
  11.             } 
  12.         } 
  13.     } 
  14.     //... 

「虛擬機(jī)棧 OperandStack」

  1. public class JvmStack { 
  2.  
  3.     private int maxSize; 
  4.     private int size
  5.     private Frame _top; 
  6.      
  7.     //... 

「棧幀 Frame」

  1. public class Frame { 
  2.  
  3.     //stack is implemented as linked list 
  4.     Frame lower
  5.  
  6.     //局部變量表 
  7.     private LocalVars localVars; 
  8.  
  9.     //操作數(shù)棧 
  10.     private OperandStack operandStack; 
  11.  
  12.     private Thread thread; 
  13.  
  14.     private Method method; 
  15.  
  16.     private int nextPC; 
  17.   
  18.     //... 
  • 關(guān)于代碼結(jié)構(gòu)看到這有點(diǎn)感覺(jué)了嗎?
  • Slot數(shù)據(jù)槽,就是一個(gè)數(shù)組結(jié)構(gòu),用于存放數(shù)據(jù)的。
  • 操作數(shù)棧、局部變量表,都是使用數(shù)據(jù)槽進(jìn)行入棧入棧操作。
  • 在棧幀里,可以看到連接、局部變量表、操作數(shù)棧、方法、線程等,那么文中說(shuō)到的當(dāng)有一個(gè)新的每一個(gè)方法在執(zhí)行的同時(shí),都會(huì)創(chuàng)建出一個(gè)棧幀,是不就對(duì)了上,可以真的理解了。
  • 如果你對(duì)JVM的實(shí)現(xiàn)感興趣,可以閱讀用Java實(shí)現(xiàn)JVM源碼:https://github.com/fuzhengwei/itstack-demo-jvm

六、jconsole監(jiān)測(cè)元空間溢出

不是說(shuō) JDK 1.8 的內(nèi)存模型把永久代下掉,換上元空間了嗎?但不測(cè)試下,就感受不到呀,沒(méi)有證據(jù)!

所有關(guān)于代碼邏輯的學(xué)習(xí),都需要有數(shù)據(jù)基礎(chǔ)和證明過(guò)程,這樣才能有深刻的印象。走著,帶你把元空間干滿,讓它OOM!

1. 找段持續(xù)創(chuàng)建大對(duì)象的代碼

  1. public static void main(String[] args) throws InterruptedException { 
  2.      
  3.     Thread.sleep(5000); 
  4.      
  5.     ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean(); 
  6.     while (true) { 
  7.         Enhancer enhancer = new Enhancer(); 
  8.         enhancer.setSuperclass(MetaSpaceOomMock.class); 
  9.         enhancer.setCallbackTypes(new Class[]{Dispatcher.class, MethodInterceptor.class}); 
  10.         enhancer.setCallbackFilter(new CallbackFilter() { 
  11.             @Override 
  12.             public int accept(Method method) { 
  13.                 return 1; 
  14.             } 
  15.             @Override 
  16.             public boolean equals(Object obj) { 
  17.                 return super.equals(obj); 
  18.             } 
  19.         }); 
  20.         System.out.println(enhancer.createClass().getName() + loadingBean.getTotalLoadedClassCount() + loadingBean.getLoadedClassCount() + loadingBean.getUnloadedClassCount()); 
  21.     } 

網(wǎng)上找了一段基于CGLIB的,你可以寫(xiě)一些其他的。

Thread.sleep(5000);,睡一會(huì),方便我們點(diǎn)檢測(cè),要不程序太快就異常了。

2. 調(diào)整元空間大小

默認(rèn)情況下元空間太大了,不方便測(cè)試出結(jié)果,所以我們把它調(diào)的小一點(diǎn)。

  1. -XX:MetaspaceSize=8m 
  2. -XX:MaxMetaspaceSize=80m 

3. 設(shè)置監(jiān)控參數(shù)

基于 jconsole 監(jiān)控,我們需要設(shè)置下參數(shù)。

  1. -Djava.rmi.server.hostname=127.0.0.1 
  2. -Dcom.sun.management.jmxremote 
  3. -Dcom.sun.management.jmxremote.port=7397 
  4. -Dcom.sun.management.jmxremote.ssl=false 
  5. -Dcom.sun.management.jmxremote.authenticate=false 

4. 測(cè)試運(yùn)行

4.1 配置參數(shù)

「以上的測(cè)試參數(shù)」,配置到IDEA中運(yùn)行程序里就可以,如下:

圖 25-5 設(shè)置程序運(yùn)行參數(shù),監(jiān)控OOM

另外,jconsole 可以通過(guò) IDEA 提供的 Terminal 啟動(dòng),直接輸入 jconsole,回車即可。

4.2 測(cè)試結(jié)果

  1. org.itstack.interview.MetaSpaceOomMock$$EnhancerByCGLIB$$bd2bb16e999099900 
  2. org.itstack.interview.MetaSpaceOomMock$$EnhancerByCGLIB$$9c774e64999199910 
  3. org.itstack.interview.MetaSpaceOomMock$$EnhancerByCGLIB$$cac97732999299920 
  4. org.itstack.interview.MetaSpaceOomMock$$EnhancerByCGLIB$$91c6a15a999399930 
  5. Exception in thread "main" java.lang.IllegalStateException: Unable to load cache item 
  6.  at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:79) 
  7.  at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) 
  8.  at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119) 
  9.  at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294) 
  10.  at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480) 
  11.  at net.sf.cglib.proxy.Enhancer.createClass(Enhancer.java:337) 
  12.  at org.itstack.interview.MetaSpaceOomMock.main(MetaSpaceOomMock.java:34) 
  13. Caused by: java.lang.OutOfMemoryError: Metaspace 
  14.  at java.lang.Class.forName0(Native Method) 
  15.  at java.lang.Class.forName(Class.java:348) 
  16.  at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:467) 
  17.  at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:339) 
  18.  at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492) 
  19.  at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:96) 
  20.  at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94) 
  21.  at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) 
  22.  at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) 
  23.  at java.util.concurrent.FutureTask.run(FutureTask.java) 
  24.  at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) 
  25.  ... 6 more 

要的就是這句,java.lang.OutOfMemoryError: Metaspace,元空間OOM,證明 JDK1.8 已經(jīng)去掉永久代,換位元空間。

4.3 監(jiān)控截圖

圖 25-6 jconsole監(jiān)測(cè)元空間溢出

圖 25-6,就是監(jiān)測(cè)程序OOM時(shí)的元空間表現(xiàn)。這回對(duì)這個(gè)元空間就有感覺(jué)了吧!

七、總結(jié)

本文從 JDK 各個(gè)版本關(guān)于內(nèi)存模型結(jié)構(gòu)的演變,來(lái)了解各個(gè)區(qū)域,包括:程序計(jì)數(shù)器、Java 虛擬機(jī)棧、本地方法棧、堆和元空間。并了解從 JDK 1.8 開(kāi)始去掉方法區(qū)引入元空間的核心目的和作用。

在通過(guò)手?jǐn)]JVM代碼的方式讓大家對(duì)運(yùn)行時(shí)數(shù)據(jù)區(qū)有一個(gè)整體的認(rèn)知,也通過(guò)這樣的方式讓大家對(duì)學(xué)習(xí)這部分知識(shí)有一個(gè)抓手。

最后我們通過(guò) jconsole 檢測(cè)元空間溢出的整個(gè)過(guò)程,來(lái)學(xué)以致用,看看元空間到底在解決什么問(wèn)題以及怎么測(cè)試。

 

責(zé)任編輯:武曉燕 來(lái)源: bugstack蟲(chóng)洞棧
相關(guān)推薦

2023-08-24 07:46:21

服務(wù)器JVM

2010-05-24 09:49:47

ADO.NET

2010-09-25 12:38:40

JVM內(nèi)存模型

2023-01-28 08:32:04

Go內(nèi)存分配

2025-03-04 10:45:19

JVM內(nèi)存模型Java

2023-11-05 12:05:35

JVM內(nèi)存

2018-07-04 14:43:55

對(duì)象模型內(nèi)存結(jié)構(gòu)內(nèi)存模型

2018-11-01 10:34:37

JVM內(nèi)存配置

2023-06-07 08:08:43

JVM內(nèi)存模型

2010-02-22 08:58:35

JVM內(nèi)存模型垃圾收集

2024-07-26 10:23:52

2010-09-26 16:42:04

JVM內(nèi)存組成JVM垃圾回收

2020-12-03 15:05:41

Kubernetes工具開(kāi)發(fā)

2023-10-23 12:28:04

數(shù)據(jù)AI

2022-02-04 22:05:19

JVM程序內(nèi)存模型

2020-03-23 13:03:55

MacBook蘋(píng)果電腦

2022-05-27 08:01:36

JVM內(nèi)存收集器

2017-09-20 08:48:09

JVM內(nèi)存結(jié)構(gòu)

2021-09-08 17:42:45

JVM內(nèi)存模型

2023-10-27 07:47:58

Java語(yǔ)言順序性
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)