一、JVM的位置及體系結構
JVM作用在作業系統之上,而Java程式作用在jvm之上,其他的程式則與jvm并列


二、類加載器,及雙親委派機制
1.類加載器
作用:加載Class檔案 -> new Student();實體的參考放在堆疊里,具體的物件放在堆里
點擊查看代碼
package com.Tang.jvm;
public class Car {
public static void main(String[] args) {
Car car1 = new Car();
Car car2 = new Car();
Car car3 = new Car();
System.out.println(car1.hashCode());
System.out.println(car2.hashCode());
System.out.println(car3.hashCode());
System.out.println("=======");
Class<? extends Car> aClass = car1.getClass();
System.out.println(car1.getClass().hashCode());
System.out.println(car2.getClass().hashCode());
System.out.println(car3.getClass().hashCode());
System.out.println("=======");
ClassLoader classLoader = aClass.getClassLoader();
System.out.println(classLoader);//jak1.8java.lang下有本地的ClassLoader類,因此AppClassLoader在其中
System.out.println(classLoader.getParent());//PlatformClassLoader 存在與jre中的ext檔案下
System.out.println(classLoader.getParent().getParent());//Bootstrap中(rt.jar)中沒有找到Car類所以回傳的是null
}
}

2.雙親委派機制
原理:在一個類運行之前會在當前加載器型別往上找(bootStrap > PlatformClassLoader >AppClassLoader),然后運行程式之后如果在最頂層沒有找到該類,則又會逐層往下找,直到AppClassLoader點擊查看代碼
package java.lang;
public class String {
//雖然在AppClassLoader中也就是本代碼中有String類,但是在類運行之前還會往上找該類是否存在,最后在bootStrap中也找到了官方的String,最后在這里運行
public String toString() {
return "hello";
}
public static void main(String[] args) {
String s = new String();
s.toString();
}
}

點擊查看代碼
package com.Tang.jvm;
public class Student {
@Override
public String toString() {
return "hello";
}
public static void main(String[] args) {
Student student = new Student();//在new Student 之后會現在bootstrap中找,發現沒有這個類,然后去ext中去找,發現也沒有,最后只能在當前應用下運行
System.out.println(student.toString());
}
}

三、Native、方法區
1.Native
凡是帶native關鍵字的,說明Java的作用范圍達不到了,==回去呼叫底層c語言的庫!==會進入本地方法堆疊,呼叫本地介面 JNI, JNI作用:擴展Java的使用,融合不同的編程語言為Java所用!最初:C、C++,java誕生的時候c、C++橫行,想要立足,必須要有呼叫C、C++的程式,于是它在記憶體區域中專門開辟了一塊標記區域:Native Method Stack ,登記native方法,在最終執行的時候,加載本地方法庫中的方法通過JNI
四、堆
1.堆的基本概念
Heap,一個JVM只有一個堆記憶體,堆記憶體的大小是可以調節的, 類加載器讀取了類之后,一般會把類,方法,常量,變數,放到堆中,類,方法,常量,變數,保存我們所有參考型別的真實物件, 垃圾的產生:比如Test test = new Test();存放在堆疊中的test若一次呼叫之后很久不會用到,那么該參考的值比如對應的年齡和姓名的值都存放在堆中,此時這些資訊都會在堆中產生垃圾 堆記憶體中還要細分為三個區域: (1)新生區(伊甸園區) (2)養老區 (3)永久區
GC垃圾回收,主要是在伊甸園區和養老區,如果記憶體滿了,就會報堆記憶體不夠!如下圖:

在jdk8以后,永久存盤區改了個名字叫元空間
2.新生區
類:誕生和成長的地方,甚至死亡 所有物件都是在這里new出來的,若此地方物件數量已經達到該區容量的最大值,則會觸發一次輕GC,也就是垃圾回收,在這程序中可能會有一些參考還會繼續使用,所以會存活下來,活下來的行程就會進入幸存者區(屬于新生區下的一個區),若幸存區也滿了又會進入養老區,若養老區還新生區都滿了就會觸發一次重GC2.永久區
這個區域常駐記憶體的,用來存放JDK自身攜帶的Class物件,Interface元資料,存盤的是Java運行時的一些環境或類資訊,這個區域不存在垃圾回收!關閉VM虛擬就會釋放這個區域的記憶體, 在永久區蹦的情況:一個啟動類加載了大量的第三方jar包,Tomcat部署了太多的應用,大量動態生成的反射類,如果不斷的被加載,直到記憶體滿,就會出現OOM例外 jdk1.6之前:永久代,車行兩次是在方法區 jdk1.7:永久代,但是慢慢的退化了,去永久代,常量池在堆中 jdk1.8之后:無永久代,常量池在元空間
點擊查看代碼
public static void main(String[] args) {
//回傳虛擬機試圖使用的最大記憶體
long max = Runtime.getRuntime().maxMemory();
//回傳jvm的初始化總記憶體
long total = Runtime.getRuntime().totalMemory();
System.out.println("max="+max+"位元組\t"+(max/(double)1024/1024)+"MB");
System.out.println("total="+total+"位元組\t"+(total/(double)1024/1024)+"MB");
//默認情況下:分配的總記憶體(最大記憶體)是電腦記憶體的1/4,而初始化的記憶體為1/64
}
運行結果圖

當遇到OOM(也就是記憶體溢位)時,解決方法如下:
(1)嘗試擴大記憶體,看是否還會繼續報錯
(2)若繼續報錯,分析記憶體,看一下哪個地方出現了問題(可能是死回圈造成空間的無限占用)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/498692.html
標籤:Java
上一篇:GUI編程詳解
下一篇:03-JDBC
