中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JVM虛擬機底層原理是什么

發布時間:2021-10-23 16:03:46 來源:億速云 閱讀:123 作者:iii 欄目:編程語言

本篇內容介紹了“JVM虛擬機底層原理是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

定義:

JVM虛擬機底層原理是什么

翻譯:首先是所有Java虛擬機線程共享的一塊區域,他存放了根類結構相關的一些信息,
有類的變量,方法信息,構造方法和構造器信息,和一些特殊方法(主要指類構造器)。
方法區在虛擬機啟動時被創建,邏輯上來講是堆的一個組成部分,但是并不強制你的具體位置,(說白了就是不同的JVM廠商在實現的時候不一定完全按照標準來創造)
最后對于內存定義:方法區在內存不足是也會拋出 OutOfMemoryError

解釋:

說了半天可能有人聽不懂了,那就來解釋一下!

拿oracle的hospost虛擬機舉例(也就是我們日常用的)

組成:

在JDK8之前hospost虛擬機對方法區的實現,叫做永久代,永久代就是使用堆的一部分空間去做實現的

JVM虛擬機底層原理是什么

而在JDK8之后把永久代移除了,換了一個實現,叫做元空間 元空間用的不是堆的內存,而是本地內存,也就是操作系統的內存

JVM虛擬機底層原理是什么

所以不同的實現對于方法區的選擇位置也不同

方法區內存溢出:

有人會疑問,方法區不就存放類的一些信息和實例嗎?大小也不足以內存溢出啊,具體什么情況,拿個例子看下

/** 元空間
 * 演示元空間內存溢出 java.lang.OutOfMemoryError: Metaspace
 * -XX:MaxMetaspaceSize=8m
 */
public class Demo1_8 extends ClassLoader { // ClassLoader可以用來加載類的二進制字節碼
	public static void main(String[] args) {
		int j = 0;
		try {
			Demo1_8 test = new Demo1_8();
			for (int i = 0; i < 10000; i++, j++) {
				// ClassWriter 作用是生成類的二進制字節碼
				ClassWriter cw = new ClassWriter(0);
				// 版本號, public, 類名, 包名, 父類, 接口
				cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);
				// 返回 byte[]
				byte[] code = cw.toByteArray();
				// 執行了類的加載
				test.defineClass("Class" + i, code, 0, code.length); // Class 對象
			}
		} finally {
			System.out.println(j);
		}
	}
}

代碼注釋都有,自行理解,由于電腦物理內存大不方便演示效果,所以要加  -XX:MaxMetaspaceSize=8m 參數

JVM1.6執行結果:永久代內存溢出導致OutOfMemoryError

JVM虛擬機底層原理是什么

JVM1.8 之后會導致元空間內存溢出 java.lang.OutOfMemoryError: Metaspace

雖然都是OutOfMemoryError 但是可以看到1.8之前是permGen space 1.8之后是Metaspace

這種場景是非常多的, 看過spring mybatis源碼的應該了解 代碼使用不當是很容易造成方法區內存溢出的

運行時常量池:

在明白運行時常量池之前首先說說什么是常量池

  • 常量池,就是一張表,虛擬機指令根據這張常量表找到要執行的類名、方法名、參數類型、字面量等信息

  • 運行時常量池,常量池是 *.class 文件中的,當該類被加載,它的常量池信息就會放入運行時常量池,并把里面的符號地址變為真實地址

了解運行時常量池之后,不得不說運行時常量池的一個重要組成部分StringTable

說StringTable先看幾道經典面試題

String s1 = "a";
String s2 = "b"; 
String s3 = "a" + "b"; 
String s4 = s1 + s2; 
String s5 = "ab"; 
String s6 = s4.intern(); // 問 
System.out.println(s3 == s4); 
System.out.println(s3 == s5); 
System.out.println(s3 == s6); 

String x2 = new String("c") + new String("d"); 
String x1 = "cd"; 
x2.intern();
// 問,如果調換了【最后兩行代碼】的位置呢,如果是jdk1.6呢 
System.out.println(x1 == x2);

講解:
①   s3 == s4  //false
s3 = "a" + "b" 兩個字符串相加 stringtable會有編譯期優化,結果就是 "ab"(字符串ab) 常量池沒有,順便入池。
s4 = s1 + s2 兩個變量拼接在運行期使用stringbuilder拼接產生新的字符串 新的字符串相當于new String("ab")出來的 所以在堆中
所以第一題為false  理由:一個在常量池中一個在堆內存中

②   s3 == s5  //true
s5 = "ab" 是一個自變量會首先檢查常量池的內容,結果常量池已經有s3拼好的"ab"了,所以s5不會創建新的對象,會直接引用常量池以有的對象,因此s3和s5都是同一個對象 所以為true

③   s3 == s6 // true
s6又是調用s4.intern()方法 intern() 方法回去常量池先看有沒有這個對象,如果有就返回常量池的對象,如果沒有就嘗試將s4進行入池,
顯然常量池已有ab,沒能入池成功,但他返回常量池中的對象,所以s6和s3就是一個對象 所以為true

④   x1 == x2  // false
x2 顯然是堆中的對象 new String("cd") ;  x1 顯然是常量池中的對象
x2調用intern方法嘗試將堆內存中的x2進行入池,但是常量池已經有了,所以沒能入池成功,所以最終 x2是堆內存中的對象 x1 是常量池中的對象 結果為false
StringTable 特性
  • 常量池中的字符串僅是符號,第一次用到時才變為對象

  • 利用串池的機制,來避免重復創建字符串對象

  • 字符串變量拼接的原理是 StringBuilder (1.8)

  • 字符串常量拼接的原理是編譯期優化

  • 可以使用 intern 方法,主動將串池中還沒有的字符串對象放入串池

    • 1.8 將這個字符串對象嘗試放入串池,如果有則并不會放入,如果沒有則放入串池, 會把串池中的對象返回

    • 1.6 將這個字符串對象嘗試放入串池,如果有則并不會放入,如果沒有會把此對象復制一份,放入串池, 會把串池中的對象返回

StringTable 位置

在JVM1.6之前stringtable在方法區,具體實現也就是永久代的其中一塊空間 而在1.7 1.8之后 他的實現空間被移動到堆內存中

為什么更改? 原因是什么?

因為永久代內存不足,而且永久代只有觸發FullGC時候才會執行他的垃圾回收,但是FullGC只有等到整個老年代的空間不足才會觸發,回收時間會很晚,間接的導致stringtable的回收效率并不高,所以1.6之后的JVM廠商對此作了優化

JVM虛擬機底層原理是什么

“JVM虛擬機底層原理是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

jvm
AI

阿克苏市| 靖远县| 准格尔旗| 阿荣旗| 抚顺县| 甘南县| 平阳县| 诸城市| 那坡县| 乾安县| 嘉黎县| 榆树市| 双江| 夏邑县| 沈阳市| 吴旗县| 淳安县| 太谷县| 政和县| 布尔津县| 大丰市| 临湘市| 阿合奇县| 门源| 金溪县| 佛山市| 垫江县| 牟定县| 安宁市| 科尔| 静乐县| 千阳县| 中宁县| 丹江口市| 南岸区| 新乡市| 图片| 修文县| 内江市| 渑池县| 库车县|