目錄
- 一、方法區
- 1、類常量池
- 2、靜態常量池
- 3、方法區過程
- 二、棧
- 三、堆
- 1、字符常量池
- 2、堆內存圖的繪制
java中內存可以分為 方法區、 堆、 棧、 程序計數器、 本地方法棧,其中比較中重要的是方法區、堆、棧。
一、方法區
1.方法區(Method Area)與Java堆一樣,是各個線程共享的內存區域。
2.方法區在JVM啟動的時候被創建,并且它的實際的物理內存空間中和Java堆區一樣都可以是不連續的。
3.方法區的大小,跟堆空間一樣,可以選擇固定大小或者可擴展。
4.方法區的大小決定了系統可以保存多少個類,加載項目中的類同時將類中的方法和屬性加載到方法區當中
5.關閉JVM就會釋放這個區域的內存。
提供兩個類Person和Test類,其中Person類定義如下:
package 內存圖;public class Person {public int age;public String name;public static int flag;public void m1() {}public static void m2() {}@Overridepublic String toString() {return "Person [age=" + age + ", name=" + name + " flag = "+flag+"]";}}
Test類定義如下:
package 內存圖;public class Test {public static void main(String[] args) {Person x1 = new Person();x1.age = 20;x1.name = "11";x1.flag = 1;Person x2 = new Person();x2.age = 22;x2.name="22";x2.flag = 2;System.out.println(x1);System.out.println(x2);change1(x1,x2);System.out.println(x1);System.out.println(x2);change2(x1,x2);System.out.println(x1);System.out.println(x2);}public static void change1(Person a,Person b) {Person temp = a;a=b;b=temp;}public static void change2(Person a,Person b) {int temp_age = a.age;String temp_name = a.name;a.age = b.age;a.name = b.name;b.age = temp_age;b.name = temp_name;}
}
分析上述的兩個類中的情況:
Person:
屬性:age(int),name(String),flag(static int)
方法:m1(),m2()(Static) ,toString()
Test:
屬性:空
方法:main()(static),change1(Peson a,Person b),change2(Person a,Person b)(static)
1、類常量池
類常量池里面存儲的是類的信息,其中存儲java類中的方法和屬性即上述的Person和Test類。其中存儲的情況如下:
其中被static靜態定義的方法和屬性標記為紅色,此時內存沒有給類分配內存地空間,因此其中定義的方法和屬性由于沒有分配內存空間不可以被使用(static定義的方法和屬性除外。)
2、靜態常量池
靜態常量池用于存儲類常量池中被static修飾過的方法和屬性,并且為這些方法和屬性分配內存空間,因此屬性被分配內存空間后,屬性會存在其類型的默認值。
3、方法區過程
類被加載到類常量池中并且獲得其中的方法和屬性,但是此時沒有給方法和屬性分配內存空間,即對象沒有被定義時無法獲得其中的沒有被static修飾過的方法和屬性,被static修飾過的會被分配內存空間,即使沒有創建對象的時候仍可以使用其中的方法和屬性
二、棧
棧有一個特點為后入先出,首先被加載到棧中的方法最后出棧,最后入棧的方法,最先出棧。main()為程序的入口,因此棧中首先加載main()方法,直到方法結束。
main()方法中的執行代碼如下:
Person x1 = new Person();x1.age = 20;x1.name = "11";x1.flag = 1;Person x2 = new Person();x2.age = 22;x2.name="22";x2.flag = 2;System.out.println(x1);System.out.println(x2);change1(x1,x2);System.out.println(x1);System.out.println(x2);change2(x1,x2);System.out.println(x1);System.out.println(x2);
根據main()方法中創建變量,創建變量如下:由于x1和x2都是非基本數據類型,因此變量中存儲的是堆中的內存地址。,當方法出棧之后,變量也會被回收。
并且main()中的方法按照順序依次執行,遇到變量時會創建變量,遇到方法時會將方法加入到棧當中。
當方法全部入棧之后:
根據后入先出:
最后:main()方法出棧,棧空
三、堆
堆內存通常有較大的空間供程序使用,其大小受限于系統的有效虛擬內存,除基礎類型以外的復雜數據類型的創建都在堆中操作,由堆分配內存空間供變量使用,例如數組、對象、字符串、列表等
1、字符常量池
字符串常量池是Java中一個重要的概念,用于優化字符串的存儲和使用。它的主要目的是提高性能和減少內存開銷。在字符串定義時,為了避免重復定義浪費空間,創建字符常量池,每一次定義字符串時會判斷字符常量池中是否包含該字符串,如果包含會直接將其內存地址賦值給變量名,不存在時會在字符常量池中創建,被創建的字符串在未被使用時不會被立刻回收。
2、堆內存圖的繪制
經過下面的代碼之后,堆中會創建出下面的情況
Person x1 = new Person();x1.age = 20;x1.name = "11";x1.flag = 1;
因為flag位于靜態常量池當中,因此創建的對象實例中不包含flag,修改時會直接修改靜態常量池中的flag。
Person x2 = new Person();x2.age = 22;x2.name="22";x2.flag = 2;System.out.println(x1);System.out.println(x2);
經過上面的代碼之后,堆中會創建出下面的情況:
并且會打印x1和x2。
change1(x1,x2);System.out.println(x1);System.out.println(x2);
經過上面的代碼之后,棧中會載入change1()的方法,堆中會創建出下面的情況:
此時x1和x2中的并未發生交換,方法結束后會消除該方法。
change2(x1,x2);System.out.println(x1);System.out.println(x2);
結束后效果如下:
x1和x2中的age和name發生交換。