国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Heim Java JavaBase JVM lernt die Java-Speicherstruktur

JVM lernt die Java-Speicherstruktur

Feb 01, 2021 pm 05:41 PM

JVM lernt die Java-Speicherstruktur

Java-Speicherstruktur

  • 1.JVM-übersicht
  • 2.Programmz?hler
    • 2.1.Definition
    • 2.2.Erkl?rung von Funktionen und Features
  • 3.Virtuell Maschinenstapel
    • 3.1. Stack-Eigenschaften
    • 3.3. Stack-Thread-Sicherheitsprobleme
    • 3.6. Thread-Laufdiagnose 6.1. Fall 1: Zu hohe CPU-Auslastung (Beispiel: Linux-System)
    • 4. Lokaler Methodenstapel .5.1. Definition
    • 5.2. Dedic-Speicherüberlauf (Outofmemoryerror: Java Heap Space)
      • 6.3. Methodenbereich-Speicherüberlauf (OutOfMemoryError: Metaspace)
    1
  • Definition :
  • Der vollst?ndige Name von JVM ist Java Virtual Machine – die Laufumgebung des Java-Programms (Java-Bin?r-Bytecode-Laufumgebung)
    • Vorteile:
    • Einmal schreiben, überall ausführen (plattformübergreifend)
    • Automatische Speicherverwaltung, Garbage-Collection-Funktion
  • Array-Index-Out-of-Bounds-Prüfung
  • Polymorphismus
    • Vergleichen Sie JVM, die Verbindung und den Unterschied zwischen JRE und JDK
    • , wir k?nnen ein Bild verwenden, um die
    • JVM-Architektur
    • zu erkl?ren, wie in gezeigt das Bild
Eine Klasse wird aus Java-Quellcode (.java-Datei) in Java kompiliert. Nach dem bin?ren Bytecode muss er den Klassenlader durchlaufen, bevor er in die JVM geladen werden kann, bevor er ausgeführt werden kann.

Normalerweise platzieren wir Klassen im Methodenbereich. Die von der Klasse in Zukunft erstellten Objekte werden im Heap abgelegt, und die Objekte im Heap verwenden beim Aufrufen von Methoden den Stapel und den Programmz?hler der virtuellen Maschine sowie die lokale Entwicklung. Bei der Ausführung der Methode wird jede Codezeile Zeile für Zeile vom Interpreter in der Ausführungs-Engine ausgeführt. Der Hotcode in der Methode ist der Code, der h?ufig aufgerufen wird und vom Just-in-Time-Compiler kompiliert und ausgeführt wird. GC wird Müll sammeln. Wir k?nnen die vom Betriebssystem bereitgestellten Funktionen über die lokale Methodenschnittstelle aufrufen.


Die Speicherstruktur von JVM umfasst: 1. Methodenbereich 2. Programmz?hler

3. Stapel virtueller Maschinen

4. Lokaler Methodenstapel

5. Heap
  • 2. Programmz?hler
  • 2.1. Definition

Programmz?hlerregister Programmz?hler (Register) Funktion:
? Es dient dazu, sich die Ausführungsadresse der n?chsten JVM-Anweisung zu merkenJVM lernt die Java-Speicherstruktur Funktionen
? Es ist Thread-privat Es kommt zu keinem Speicherüberlauf (Der einzige in der Speicherstruktur, die keine Speicherüberlaufstruktur verursacht)
JVM lernt die Java-SpeicherstrukturIn 2.2 erkl?ren wir die Funktion und Eigenschaften des Programmz?hlers.


2.2. Erkl?rung der Funktionen und Features

?二進(jìn)制字節(jié)碼			JVM指令					Java源代碼?0:?getstatic?????#20?????????????????//?PrintStream?out?=?System.out;?
?3:?astore_1??????????????????????????//?-?
?4:?aload_1???????????????????????????//?out.println(1);?
?5:?iconst_1??????????????????????????//?-?
?6:?invokevirtual?#26?????????????????//?-?
?9:?aload_1???????????????????????????//?out.println(2);?
?10:?iconst_2??????????????????????????//?-
?11:?invokevirtual?#26?????????????????//?-
?14:?aload_1???????????????????????????//?out.println(3);?
?15:?iconst_3??????????????????????????//?-
?16:?invokevirtual?#26?????????????????//?-
?19:?aload_1???????????????????????????//?out.println(4);?
?20:?iconst_4??????????????????????????//?-
?21:?invokevirtual?#26?????????????????//?-
?24:?aload_1???????????????????????????//?out.println(5);?
?25:?iconst_5??????????????????????????//?-
?26:?invokevirtual?#26?????????????????//?-
?29:?return

Die erste Zeile von System.out weist einer Variablen einen Wert zu und ruft die Methode println() auf. Geben Sie dann nacheinander 1,2,3,4,5 aus. Diese Anweisungen k?nnen nicht direkt zur Ausführung an die CPU übergeben werden und müssen den Interpreter durchlaufen. Es ist dafür verantwortlich, Bytecode-Anweisungen einzeln in Maschinencode zu interpretieren. Anschlie?end kann der Maschinencode zur Ausführung an die CPU übergeben werden. Das hei?t

Bin?rer Bytecode->Interpreter->Maschinencode->CPU

Tats?chlich besteht die Funktion des Programmz?hlers darin, sich w?hrend der Ausführung des Befehls die Ausführungsadresse des n?chsten JVM-Befehls zu merken.
Die Zahlen 0, 3, 4 vor unserem bin?ren Bytecode oben... wir k?nnen sie als Adressen verstehen. Anhand dieser Adressinformationen k?nnen wir den auszuführenden Befehl finden.

Jedes Mal, wenn eine Anweisung abgerufen und zur Ausführung an die CPU übergeben wird, fügt der Programmz?hler die Adresse der n?chsten Anweisung in den Programmz?hler ein. Nachdem die Ausführung einer Anweisung abgeschlossen ist, ruft der Interpreter die n?chste Anweisung ab der Programmz?hler. Die Adresse der Anweisung. Anschlie?end wird es vom Interpreter in Maschinencode interpretiert und anschlie?end zur Ausführung an die CPU übergeben. Dann wiederholen Sie diesen Vorgang immer wieder

. Physikalisch wird der Programmz?hler durch Register implementiert. Register sind die am schnellsten lesbaren Speichereinheiten in der CPU-Komponente

.

程序計(jì)數(shù)器是線程私有的
假如說(shuō)上述代碼都在線程1中運(yùn)行,同時(shí)運(yùn)行的還有線程2和線程3,多個(gè)線程運(yùn)行的時(shí)候,CPU會(huì)給每個(gè)線程分配時(shí)間片,給線程1分配時(shí)間片,如果線程1在指定的時(shí)間沒(méi)有運(yùn)行完,它就會(huì)把狀態(tài)暫存,切換到線程2,線程2執(zhí)行自己的代碼。線程2執(zhí)行完了,再繼續(xù)執(zhí)行線程1的代碼,在線程切換的過(guò)程中,我們要記住下一條指令的執(zhí)行地址。就需要用到程序計(jì)數(shù)器。假如說(shuō)線程1剛開始執(zhí)行到第9行代碼,恰好這個(gè)時(shí)候時(shí)間片用完,CPU切換到線程2去執(zhí)行,這時(shí)它就會(huì)把下一條指令的地址10記錄到程序計(jì)數(shù)器里面,而且程序計(jì)數(shù)器是線程私有的,它是屬于線程1的,等線程2代碼執(zhí)行完了,線程1搶到了時(shí)間片,它就會(huì)從自己的程序計(jì)數(shù)器里面取出下一行代碼。每個(gè)線程都有自己的程序計(jì)數(shù)器

3.虛擬機(jī)棧

3.1.棧的特點(diǎn)

棧類似現(xiàn)實(shí)生活中的子彈夾。棧最重要的特點(diǎn)是后進(jìn)先出。
JVM lernt die Java-Speicherstruktur
如圖,1是最先進(jìn)入棧中的,3是最后進(jìn)入棧中的,但是在出棧的時(shí)候,3最先出棧,1最后出棧。即他們按照1,2,3的順序入棧,按照3,2,1的順序出棧

虛擬機(jī)棧就是我們線程運(yùn)行時(shí)需要的內(nèi)存空間,一個(gè)線程運(yùn)行時(shí)需要一個(gè)棧。如果將來(lái)有多個(gè)線程的話,它就會(huì)有多個(gè)虛擬機(jī)棧。
每個(gè)??梢钥闯墒怯啥鄠€(gè)棧幀組成,例如上圖中每個(gè)元素1,2,3都可以看成是棧幀。
一個(gè)棧幀就對(duì)應(yīng)著Java中一個(gè)方法的調(diào)用,即棧幀就是每個(gè)方法運(yùn)行時(shí)需要的內(nèi)存。每個(gè)方法運(yùn)行時(shí)需要的內(nèi)存一般有參數(shù),局部變量,返回地址,這些都需要占用內(nèi)存,所以每個(gè)方法執(zhí)行時(shí),都要預(yù)先把這些內(nèi)存分配好。
當(dāng)我們調(diào)用第一個(gè)方法棧幀時(shí),它就會(huì)給第一個(gè)方法分配棧幀空間,并且壓入棧內(nèi),當(dāng)這個(gè)方法執(zhí)行完了,就會(huì)把這個(gè)方法棧幀出棧,釋放這個(gè)方法所占用的內(nèi)存。
一個(gè)棧內(nèi)可能有多個(gè)棧幀存在。

總結(jié)
Java Virtual Machine Stacks(Java虛擬機(jī)棧)

  • 每個(gè)線程運(yùn)行時(shí)所需要的內(nèi)存,稱為虛擬機(jī)棧
  • 每個(gè)棧由多個(gè)棧幀(Frame)組成,對(duì)應(yīng)著每次方法調(diào)用時(shí)所占用的內(nèi)存
  • 每個(gè)線程只能有一個(gè)活動(dòng)棧幀,對(duì)應(yīng)著當(dāng)前正在執(zhí)行的那個(gè)方法(位于棧頂)

活動(dòng)棧幀表示線程正在執(zhí)行的方法。

3.2.棧的演示

public?class?teststacks?{
	public?static?void?main(String[]?args)?throws?InterruptedException{
		method1();
	}
	public?static?void?method1(){
		method2(1,2);
	}
	public?static?int?method2(int?a,int?b){
		int?c=a+b;
		return?c;
	}}

可以自行調(diào)試以上代碼來(lái)觀察棧中的變化情況。
入棧順序:main->method1->method2
出棧順序:method2->method1->main

3.3.棧的問(wèn)題辨析

  1. 垃圾回收是否涉及棧內(nèi)存?
    不涉及,垃圾回收只是回收堆內(nèi)存中的無(wú)用對(duì)象,棧內(nèi)存不需要對(duì)它執(zhí)行垃圾回收,隨著方法的調(diào)用結(jié)束,棧內(nèi)存就釋放了。
  2. 棧內(nèi)存分配越大越好嗎?
    首先棧內(nèi)存可以指定:-Xss size(如果不指定棧內(nèi)存大小,不同系統(tǒng)會(huì)有一個(gè)不同的默認(rèn)值)
    其次由于電腦內(nèi)存一定,假如有100Mb,如果給棧內(nèi)存指定為2Mb,則最多只能存在50個(gè)線程,所以并不是越大越好,棧內(nèi)存較大一般是可以進(jìn)行較多次的方法遞歸調(diào)用,而不會(huì)增強(qiáng)線程效率,反而會(huì)使線程數(shù)量減少,一般使用默認(rèn)大小。

3.4.棧的線程安全問(wèn)題

看一個(gè)變量是否線程安全,首先就是看這個(gè)變量對(duì)多個(gè)線程是共享的還是私有的,共享的變量需要考慮線程安全。
其次局部變量也不能保證是線程安全的,需要看此變量是否逃離了方法的作用范圍(作為參數(shù)和返回值逃出方法作用范圍時(shí)需要考慮線程安全問(wèn)題)
例如:
以下代碼中局部變量是私有的,是線程安全的

	//多個(gè)線程同時(shí)執(zhí)行該方法,會(huì)不會(huì)造成x值混亂呢?
	//不會(huì),因?yàn)閤是方法內(nèi)的局部變量,是線程私有的,互不干擾
	static?void?m1(){
		int?x=0;
		for(int?i=0;i<p>但是如果我們把變量的類型改為static,此時(shí)就大不一樣了,x是靜態(tài)變量,線程1和線程2同時(shí)擁有同一個(gè)x,static變量針對(duì)多個(gè)線程是一個(gè)共享的,不加安全保護(hù)的話,就會(huì)出現(xiàn)線程安全問(wèn)題。</p><pre class="brush:php;toolbar:false">	static?void?m1(){
		static?int?x=0;
		for(int?i=0;i<p>我們?cè)倏磶讉€(gè)方法</p><pre class="brush:php;toolbar:false">public?static?void?main(String[]?args)?{
????????StringBuilder?sb?=?new?StringBuilder();
????????sb.append(4);
????????sb.append(5);
????????sb.append(6);
????????new?Thread(()->{
????????????m2(sb);
????????}).start();
????}
????public?static?void?m1()?{
????????StringBuilder?sb?=?new?StringBuilder();
????????sb.append(1);
????????sb.append(2);
????????sb.append(3);
????????System.out.println(sb.toString());
????}
????public?static?void?m2(StringBuilder?sb)?{
????????sb.append(1);
????????sb.append(2);
????????sb.append(3);
????????System.out.println(sb.toString());
????}
????public?static?StringBuilder?m3()?{
????????StringBuilder?sb?=?new?StringBuilder();
????????sb.append(1);
????????sb.append(2);
????????sb.append(3);
????????return?sb;
????}

m1是線程安全的:m1中的sb是線程中的局部變量,它是屬于線程私有的
m2線程不安全:sb它是方法的參數(shù),有可能有其它的線程訪問(wèn)到它,它就不再是線程私有的了,它對(duì)多個(gè)線程是共享的。
m3不是線程安全的:它被當(dāng)成返回結(jié)果返回了,返回了有可能其它的線程拿到這個(gè)對(duì)象,從而并發(fā)的修改。

3.5.棧內(nèi)存溢出(StackOverflowError)

什么情況下會(huì)導(dǎo)致棧內(nèi)存溢出吶?
1.棧幀過(guò)多導(dǎo)致棧內(nèi)存溢出(一般遞歸調(diào)用次數(shù)太多,進(jìn)棧太多導(dǎo)致溢出)
這里最容易出現(xiàn)的場(chǎng)景是函數(shù)的遞歸調(diào)用。
2.棧幀過(guò)大導(dǎo)致棧內(nèi)存溢出(不太容易出現(xiàn))

棧內(nèi)存溢出代碼演示1(自己開發(fā)):
測(cè)試以下的程序,其中遞歸函數(shù)沒(méi)有遞歸邊界

public?class?Demo1_2?{
	private?static?int?count;
????public?static?void?main(String[]?args)?{
????????try?{
????????????method1();
????????}?catch?(Throwable?e)?{
????????????e.printStackTrace();
????????????System.out.println(count);
????????}
????}
????private?static?void?method1()?{
????????count++;
????????method1();
????}}

運(yùn)行結(jié)果如下
JVM lernt die Java-Speicherstruktur

JVM lernt die Java-Speicherstruktur
這里報(bào)了錯(cuò)誤StackOverflowError。
總共進(jìn)行了22846次遞歸調(diào)用

idea中設(shè)置棧內(nèi)存大?。?/strong>
JVM lernt die Java-Speicherstruktur
將棧內(nèi)存設(shè)置的小一點(diǎn),發(fā)現(xiàn)5000多次遞歸調(diào)用就溢出了。

棧內(nèi)存溢出代碼演示2(第三方依賴庫(kù)出現(xiàn)):
JVM lernt die Java-Speicherstruktur
本案例可以使用JsonIgnore注解解決循環(huán)依賴,數(shù)據(jù)轉(zhuǎn)換時(shí),只讓部門類去關(guān)聯(lián)員工類,員工類不再關(guān)聯(lián)部門類,在員工類的部門屬性(dept)上加@JsonIgnore注解。具體使用詳情可以點(diǎn)擊此處查看

3.6.線程運(yùn)行診斷

3.6.1.案例1:cpu占用過(guò)多(linux系統(tǒng)為例)

排查步驟:

1.在linux中使用top命令,去查看后臺(tái)進(jìn)程對(duì)cpu的占用情況
注意,在這之前我們運(yùn)行了一道Java程序
JVM lernt die Java-Speicherstruktur
Java代碼占用了CPU的99.3%.top命令只能定位到進(jìn)程,而無(wú)法定位到線程。

2.查看線程對(duì)cpu的占用情況:ps H -eo pid,tid,%cpu
如果顯示過(guò)多,可使用ps H -eo pid,tid,%cpu | grep 進(jìn)程id,過(guò)濾掉不想看的部分進(jìn)程

注意:ps不僅可以查看進(jìn)程,也可以查看線程對(duì)CPU的占用情況。H把進(jìn)程中的線程所有信息都展示出來(lái)。-eo規(guī)定輸出感興趣的內(nèi)容,這里我們想看看pid,tid和CPU的占用情況%cpu
JVM lernt die Java-Speicherstruktur
當(dāng)線程數(shù)太多,排查不方便的話,我們可以用grep pid來(lái)進(jìn)行篩選,過(guò)濾掉不感興趣的進(jìn)程
ps H -eo pid,tid,%cpu |grep 32655

3.定位到是哪個(gè)線程占用內(nèi)存過(guò)高后,再使用Jdk提供的命令(jstack+進(jìn)程id)去查看進(jìn)程中各線程的運(yùn)行信息,需要把第二步中查到的線程id(十進(jìn)制)轉(zhuǎn)為十六進(jìn)制,然后進(jìn)行比較查詢到位置后判斷異常信息。
JVM lernt die Java-Speicherstruktur
thread1,thread2,thread3是我們自己定義的線程。
可以根據(jù)線程id,找到有問(wèn)題的線程,進(jìn)一步定位到問(wèn)題代碼的源碼行號(hào)
JVM lernt die Java-Speicherstruktur

3.6.2.案例2:線程診斷_遲遲得不到結(jié)果

仍然通過(guò)jdk提供的 jstack+進(jìn)程id的方式,去查看進(jìn)程中各個(gè)線程的運(yùn)行信息
JVM lernt die Java-Speicherstruktur
JVM lernt die Java-Speicherstruktur

4.本地方法棧

含義:Java虛擬機(jī)調(diào)用本地方法時(shí),需要給本地方法提供的一些內(nèi)存空間
本地方法不是由Java編寫的代碼,由于Java有時(shí)不能直接和操作系統(tǒng)打交道,所以需要用C/C++語(yǔ)言來(lái)與操作系統(tǒng)打交道,那么Java就可以通過(guò)調(diào)用本地方法來(lái)獲得這些功能。本地方法非常的多,如Object類的clone(),hashCode方法,wait方法,notify方法等

public?native?int?hashCode();

5.堆

5.1.定義

1.虛擬機(jī)棧,程序計(jì)數(shù)器,本地方法棧,這些都是線程私有的,而堆和方法區(qū),是線程公用的一塊內(nèi)存區(qū)域。
2.通過(guò)new關(guān)鍵字創(chuàng)建的對(duì)象都會(huì)使用堆內(nèi)存
3.由于堆是線程共享的,堆內(nèi)的對(duì)象都要考慮線程安全問(wèn)題(也有一些例外)
4.堆有垃圾回收機(jī)制,不再被引用的對(duì)象會(huì)被回收

5.2.堆內(nèi)存溢出(OutOfMemoryError:Java heap space)

對(duì)象一直存在于堆中未被回收,且占用內(nèi)存越來(lái)越大,最終導(dǎo)致堆內(nèi)存溢出(雖然堆中有垃圾回收機(jī)制,但垃圾回收機(jī)制不是回收所有的對(duì)象)
我們可以看看下面的代碼

public?static?void?main(String[]?args)?{
????????int?i?=?0;
????????try?{
????????????List<string>?list?=?new?ArrayList();
????????????String?a?=?"hello";
????????????while?(true)?{
????????????????list.add(a);?//?hello,?hellohello,?hellohellohellohello?...
????????????????a?=?a?+?a;??//?hellohellohellohello
????????????????i++;
????????????}
????????}?catch?(Throwable?e)?{
????????????e.printStackTrace();
????????????System.out.println(i);
????????}}</string>

JVM lernt die Java-Speicherstruktur
報(bào)了錯(cuò)誤java.lang.OutOfMemoryError
代碼中每次都拼接一個(gè)hello,由于定義的list集合創(chuàng)建在try語(yǔ)句里面,所以在for循環(huán)不斷執(zhí)行過(guò)程中,list集合是不會(huì)被回收的,只要程序還沒(méi)到catch之前,它就一直有效。而字符串對(duì)象都被追加到了集合內(nèi)部,字符串對(duì)象由于一直被使用,所以不會(huì)被回收。
我們可以通過(guò)-Xmx來(lái)設(shè)置堆空間大小。
JVM lernt die Java-Speicherstruktur
我們把堆內(nèi)存改成8M(之前內(nèi)存是4G),此時(shí)只運(yùn)行了17次。

5.3.堆內(nèi)存診斷

1.jps工具:jps,查看當(dāng)前進(jìn)程中有哪些Java進(jìn)程,并將進(jìn)程id顯示出來(lái)(idea中通過(guò)terminal命令行輸入命令)
2.jmap工具:jmap -heap 進(jìn)程id 查詢某一個(gè)時(shí)刻堆內(nèi)存的占用情況
3.jconsole工具:圖形界面的,多功能監(jiān)測(cè)工具,可連續(xù)監(jiān)測(cè),使用流程圖如下(1-2-3):

6.方法區(qū)

6.1.定義

方法區(qū)(Method Area)與Java堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域,他用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)常量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。(與類有關(guān)的信息)。雖然Java虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分,但是他卻有一個(gè)別名叫做Non-Heap(非堆),目的應(yīng)該是與Java堆區(qū)分開來(lái)。方法區(qū)在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。
對(duì)于習(xí)慣在HotSpot虛擬機(jī)上開發(fā)、部署程序的開發(fā)者來(lái)說(shuō),很多都更愿意把方法取稱為“永久代”(Permanent Generation),本質(zhì)上兩者并不等價(jià),僅僅是因?yàn)镠otSpot虛擬機(jī)的設(shè)計(jì)團(tuán)隊(duì)選擇把GC分代收集擴(kuò)展至方法區(qū),或者說(shuō)使用永久代來(lái)實(shí)現(xiàn)方法區(qū)而已,這樣HotSpot的垃圾收集器可以像管理Java堆一樣管理這部分內(nèi)存,能夠省去專門為方法區(qū)編寫內(nèi)存管理代碼的工作。對(duì)于其他虛擬機(jī)(如BEA JRockit、IBM J9等)來(lái)說(shuō)是不存在永久代的概念的。原則上,如何實(shí)現(xiàn)方法區(qū)屬于虛擬機(jī)實(shí)現(xiàn)細(xì)節(jié),不受虛擬機(jī)規(guī)范約束,但使用永久代來(lái)實(shí)現(xiàn)方法區(qū),現(xiàn)在看來(lái)并不是一個(gè)好主意,因?yàn)檫@樣更容易遇到內(nèi)存溢出問(wèn)題(永久代有-XX:MaxPermSize的上限,J9和JRockit只要沒(méi)有觸碰到進(jìn)程可用內(nèi)存的上限,例如32位系統(tǒng)中的4GB,就不會(huì)出現(xiàn)問(wèn)題),而且有極少數(shù)方法(例如String.intern())會(huì)因這個(gè)原因?qū)е虏煌摂M機(jī)下有不同的表現(xiàn)。因此,對(duì)于HotSpot虛擬機(jī),根據(jù)官方發(fā)布的路線圖信息,現(xiàn)在也已放棄永久代并逐步改為采用Navtive Memory來(lái)實(shí)現(xiàn)方法區(qū)的規(guī)劃,在JDK1.7的HostSpot中,已經(jīng)把原本放在永久代的字符串常量池移出,jdk1.8中后稱作元空間,用的操作系統(tǒng)內(nèi)存。
Java虛擬機(jī)規(guī)范對(duì)方法區(qū)的限制非常寬松,除了和Java堆一樣不需要連續(xù)的內(nèi)存和可以喧囂而固定大小或者可擴(kuò)展外,還可以選擇不實(shí)現(xiàn)垃圾收集。相對(duì)而言,垃圾收集行為在這個(gè)區(qū)域是比較少出現(xiàn)的,但并非數(shù)據(jù)進(jìn)入了方法區(qū)就如永久代的名字一樣“永久”存在了。這區(qū)域的內(nèi)存回收目標(biāo)主要是針對(duì)常量池的回收和對(duì)類型的卸載,一般來(lái)說(shuō),這個(gè)區(qū)域的回收“成績(jī)”比較難以令人滿意,尤其是類型的卸載,條件相當(dāng)苛刻,但是這部分區(qū)域的回收確實(shí)是必要的。在Sun公司的BUG列表中,曾出現(xiàn)過(guò)的若干個(gè)嚴(yán)重的BUG就是由于低版本的HotSpot虛擬機(jī)對(duì)此區(qū)域未完全回收而導(dǎo)致內(nèi)存泄漏。
根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定,當(dāng)方法區(qū)無(wú)法滿足內(nèi)存分配需求時(shí),將拋出OutOfMemoryError異常。

文原文關(guān)于虛擬機(jī)的定義:

JVM lernt die Java-Speicherstruktur

6.2.定義

jdk1.8之前,方法區(qū)是用的堆內(nèi)存,1.8之后,方法區(qū)用的操作系統(tǒng)內(nèi)存。
這塊不是太清晰,可以參考下此篇博客點(diǎn)擊查看
常量池分為靜態(tài)常量池和動(dòng)態(tài)常量池,下圖中的常量池指的是動(dòng)態(tài)常量池,因?yàn)樗鼈円呀?jīng)被讀入內(nèi)存中去,而靜態(tài)常量池存在于class文件中
JVM lernt die Java-Speicherstruktur

6.3.方法區(qū)內(nèi)存溢出(OutOfMemoryError: Metaspace)

1.8以前會(huì)導(dǎo)致永久代內(nèi)存溢出

1.8以后會(huì)導(dǎo)致元空間內(nèi)存溢出

/**
?*?演示元空間內(nèi)存溢出?java.lang.OutOfMemoryError:?Metaspace
?*?-XX:MaxMetaspaceSize=8m
?*/public?class?Demo1_8?extends?ClassLoader?{?//?可以用來(lái)加載類的二進(jìn)制字節(jié)碼
????public?static?void?main(String[]?args)?{
????????int?j?=?0;
????????try?{
????????????Demo1_8?test?=?new?Demo1_8();
????????????
????????????for?(int?i?=?0;?i?<p><strong>jdk1.8以后, 默認(rèn)情況下,方法區(qū)用的是系統(tǒng)內(nèi)存,所以加大還是不會(huì)導(dǎo)致內(nèi)存溢出,循環(huán)很多次都運(yùn)行成功。</strong><br><strong>當(dāng)設(shè)置了-XX:MaxMetaspaceSize=8m,到了5411次就溢出了。報(bào)的是java.lang.OutOfMemoryError: Metaspace錯(cuò)誤</strong></p><p>而1.8以前永久代溢出報(bào)的錯(cuò)誤是java.lang.OutOfMemoryError:PermGen space</p><p><strong>6.4.常量池</strong></p><p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/052/b93dd11973d3f8094228c146b3131c12-17.png" class="lazy" alt="JVM lernt die Java-Speicherstruktur"></p><p><strong>常量池,就是一張表,虛擬機(jī)指令根據(jù)這站常量表找到要執(zhí)行的類名、方法名、參數(shù)類型、字面量信息(如字符串常量、true和false)</strong>。<br><em><em>運(yùn)行時(shí)常量池,常量池是</em>.class文件中的,當(dāng)該類被加載,它的常量池信息就會(huì)放入運(yùn)行時(shí)常量池,并把里面的符號(hào)地址變?yōu)檎鎸?shí)地址</em>*。</p><pre class="brush:php;toolbar:false">public?class?HelloWorld?{
	public?static?void?main(String[]?args)?{
		System.out.println("hello,world");
	}}

以上是一個(gè)helloworld程序,helloworld要運(yùn)行,肯定要先編譯成一個(gè)二進(jìn)制字節(jié)碼。
二進(jìn)制字節(jié)碼由類的基本信息、常量池、類方法定義(包含了虛擬機(jī)指令)。
反編譯HelloWorld(之前需要運(yùn)行將.java文件編譯成.class文件)
使用idea工具
JVM lernt die Java-Speicherstruktur

F:\IDEA\projects\jvm>javap?-v?F:\IDEA\projects\jvm\out\production\untitled\HelloWorld.class

F:\IDEA\projects\jvm\out\production\untitled\是HelloWorld.class所在的路徑

顯示類的詳細(xì)信息

Classfile?/F:/IDEA/projects/jvm/out/production/untitled/HelloWorld.class
??Last?modified?2021-1-30;?size?533?bytes
??MD5?checksum?82d075eb7217b4d23706f6cfbd44f8f1
??Compiled?from?"HelloWorld.java"public?class?HelloWorld
??minor?version:?0
??major?version:?52
??flags:?ACC_PUBLIC,?ACC_SUPER

可以看到類的文件,最后修改時(shí)間,簽名。以及版本等等。有的還有訪問(wèn)修飾符、父類和接口等詳細(xì)信息。

顯示常量池

Constant?pool:
???#1?=?Methodref??????????#6.#20?????????//?java/lang/Object."<init>":()V
???#2?=?Fieldref???????????#21.#22????????//?java/lang/System.out:Ljava/io/PrintStream;
???#3?=?String?????????????#23????????????//?hello,world
???#4?=?Methodref??????????#24.#25????????//?java/io/PrintStream.println:(Ljava/lang/String;)V
???#5?=?Class??????????????#26????????????//?HelloWorld
???#6?=?Class??????????????#27????????????//?java/lang/Object
???#7?=?Utf8???????????????<init>
???#8?=?Utf8???????????????()V
???#9?=?Utf8???????????????Code
??#10?=?Utf8???????????????LineNumberTable
??#11?=?Utf8???????????????LocalVariableTable
??#12?=?Utf8???????????????this
??#13?=?Utf8???????????????LHelloWorld;
??#14?=?Utf8???????????????main
??#15?=?Utf8???????????????([Ljava/lang/String;)V
??#16?=?Utf8???????????????args
??#17?=?Utf8???????????????[Ljava/lang/String;
??#18?=?Utf8???????????????SourceFile
??#19?=?Utf8???????????????HelloWorld.java
??#20?=?NameAndType????????#7:#8??????????//?"<init>":()V
??#21?=?Class??????????????#28????????????//?java/lang/System
??#22?=?NameAndType????????#29:#30????????//?out:Ljava/io/PrintStream;
??#23?=?Utf8???????????????hello,world
??#24?=?Class??????????????#31????????????//?java/io/PrintStream
??#25?=?NameAndType????????#32:#33????????//?println:(Ljava/lang/String;)V
??#26?=?Utf8???????????????HelloWorld
??#27?=?Utf8???????????????java/lang/Object
??#28?=?Utf8???????????????java/lang/System
??#29?=?Utf8???????????????out
??#30?=?Utf8???????????????Ljava/io/PrintStream;
??#31?=?Utf8???????????????java/io/PrintStream
??#32?=?Utf8???????????????println
??#33?=?Utf8???????????????(Ljava/lang/String;)V</init></init></init>

顯示方法定義

{
??public?HelloWorld();
????descriptor:?()V
????flags:?ACC_PUBLIC
????Code:
??????stack=1,?locals=1,?args_size=1
?????????0:?aload_0?????????1:?invokespecial?#1??????????????????//?Method?java/lang/Object."<init>":()V
?????????4:?return
??????LineNumberTable:
????????line?1:?0
??????LocalVariableTable:
????????Start??Length??Slot??Name???Signature????????????0???????5?????0??this???LHelloWorld;

??public?static?void?main(java.lang.String[]);
????descriptor:?([Ljava/lang/String;)V
????flags:?ACC_PUBLIC,?ACC_STATIC
????Code:
??????stack=2,?locals=1,?args_size=1
?????????0:?getstatic?????#2??????????????????//?Field?java/lang/System.out:Ljava/io/PrintStream;
?????????3:?ldc???????????#3??????????????????//?String?hello,world
?????????5:?invokevirtual?#4??????????????????//?Method?java/io/PrintStream.println:(Ljava/lang/String;)V
?????????8:?return
??????LineNumberTable:
????????line?3:?0
????????line?4:?8
??????LocalVariableTable:
????????Start??Length??Slot??Name???Signature????????????0???????9?????0??args???[Ljava/lang/String;}</init>

第一個(gè)方法是public HelloWorld();它是編譯器自動(dòng)為我們構(gòu)造的無(wú)參構(gòu)造方法。
第二個(gè)是public static void main(java.lang.String[]);即main方法
方噶里面就包括了虛擬機(jī)的指令了。
getstatic獲取一個(gè)靜態(tài)變量,即獲取System.out靜態(tài)變量
ldc是加載一個(gè)參數(shù),參數(shù)是字符串hello,world
invokevirtual虛方法調(diào)用,println方法
return執(zhí)行結(jié)束。
我們getstatic、ldc、invokevirtual后面都有一個(gè)#2,#3,#4。在解釋器翻譯這些虛擬機(jī)指令的時(shí)候,它會(huì)把這些#2,#3,#4進(jìn)行一個(gè)查表翻譯。比如getstatic #2,就去查常量池的表。在常量池中
#2 = Fieldref #21.#22 引用的是成員變量#21,#22.
#21 = Class #28 // java/lang/System
#22 = NameAndType #29:#30 // out:Ljava/io/PrintStream;
然后再去找#28.29,30
#28 = Utf8 java/lang/System
#29 = Utf8 out
#30 = Utf8 Ljava/io/PrintStream;
所以現(xiàn)在我就知道了,我是要找到j(luò)ava.lang.system類下叫out的成員變量,類型是java/io。
同理,ldc是找#3 = String #23 Utf8 hello,world,它是虛擬機(jī)常量池的一個(gè)字符串。把helloworld常量變成字符串對(duì)象加載進(jìn)來(lái)。
invokevirtual #4 Methodref #24.#25 等等
所以常量池的作用就是給我們指令提供一些常量符號(hào),根據(jù)這些常量符號(hào),我們就可以根據(jù)查表的方式去找到它,這樣虛擬機(jī)才能成功的執(zhí)行它。

相關(guān)免費(fèi)學(xué)習(xí)推薦:java基礎(chǔ)教程

Das obige ist der detaillierte Inhalt vonJVM lernt die Java-Speicherstruktur. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erkl?rung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Hei?e KI -Werkzeuge

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Clothoff.io

Clothoff.io

KI-Kleiderentferner

Video Face Swap

Video Face Swap

Tauschen Sie Gesichter in jedem Video mühelos mit unserem v?llig kostenlosen KI-Gesichtstausch-Tool aus!

Hei?e Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Hei?e Themen

PHP-Tutorial
1502
276