Java記憶體結構、類的初始化、及物件建構過程,java構造
網上關於該題目的文章已經很多,我覺得把它們幾個關聯起來講可能更好理解一下。與其它語言一樣,它在執行我們寫的程式前要先分配記憶體空間,以便於存放代碼、資料;程式的執行過程其實依然是代碼的執行及資料的讀寫過程;除了在執行我們寫的顯式的可見代碼外,Jvm還會自動幫我們幫一些事,包括類的載入、初始化、GC等,這些也不特殊。以下分別來說下這些概念。
這一點基本上同其它進階語言一樣,Java包含:堆、棧、本地棧(有些特殊)、永久代碼區。以下具體說下每個記憶體區的作用及使用方式
| |
概念 |
修改方式 |
永久代碼區 permanent space |
其實代碼兩個字是我加上去的,它並不是單單存放代碼,但代碼的確是最主要、最典型的、對於一個類A,不論執行個體化多少對象,它的代碼區有始自終都只有一塊。這個區包含的主要是類的資訊、比如static欄位,final常量(跟編譯器還是有些關係),各種方法(包括static及無static修飾的)二進位天書等,這一地區往往在整個JVM執行過程中大小不變。 |
XX:PermSpace 及 XX:MaxPermSpace |
本地棧 native stack |
用於java native線程,也就是用jni裡添加的線程使用的棧,因為本人沒寫過多少jni代碼,這塊不詳說。 |
? |
棧 stack |
說到棧必須關聯線程,線程包含我們平時常用的主線程main、及我們調用Thread.start()運行起來的一般線程,一個線程一個棧;棧的作用大家應該清楚,就是用來保留我們線程執行的現場,包括:調用者函數的局部變數、參數等;棧的特色是存放的東西都很小,存取速度很快。 |
Xss 及 -XX:MainThreadStackSize |
堆 heap |
堆,應該是記憶體是佔用最大的一個部分,跟據jvm的配置不同,堆可佔到jvm總使用記憶體的95%以上,當然這個數字沒多大意義,只是給大家一個感覺,相對於其它語言,Java裡的堆比較好理解,所有我們new出來的對象都存放在堆裡,而它的使用者通過"引用"來調用它,引進會經常被壓入之前我們提到的棧裡(引用很小,所以很適合在棧裡進進出出)。 |
Xms 初始大小 及 Xmx 最大值 及 Xmn 年輕代大小 |
*注意:32位的機器記憶體設定的總合一般不能大於1.5G(即使你有4G的實體記憶體,可能跟java的定址方式有關;是否有其它解決方案,還望高人給出)
我這裡舉個例子
public class Demo { // 永久代碼區 <- 類總體資訊
public static String staticField; // 永久代碼區
public String dynField; // 堆
public static void staticMtd() { // 永久代碼區 <- 代碼塊
int i = 0; //直接量引用(程式員不可見)往往在寄存器裡,或是其它臨時的地方
String str = ""; //str的執行個體在堆裡
System.out.println("我現在在調用另一個方法");//此時i、str的引用被壓到棧裡, str的執行個體在堆裡
}
public void mtd() { // 永久代碼區 <- 代碼塊(但加了訪問限制,只有用對象才能引用到該代碼塊)
}
}
完成了這部分,剩下的兩部分就想對簡單了:
類在第一次使用之前被載入初始化,具體怎麼載入取決於運行環境。類的初始化即在永久代碼區裡為類及欄位分配記憶體空間,然後再跟據我們的書寫順序依次賦值或執行static塊。
比如:
static{ System.out.println("first exc"); }
static String Field = "x";
static String F2 = Field;
static{System.out.println("after F2=Field");}
//賦值及執行順序就是書寫順序。
構造子類之前必須調用父類,且構造塊會建構函式之前執行(很想知道具體是怎麼實現的,望大師指點)
舉個例子:
A類:
public class A {
static {
System.out.println("A static block");
}
public A() {
super();
System.out.println("A constructor");
}
{
System.out.println("A not static block" + this);
}
}
B類:
public class B extends A {
static {
System.out.println("B static block");
}
public B() {
super();
System.out.println("B constructor");
}
{
System.out.println("B not static block");
}
public static void main(String[] args) {
new B();
}
}
結果:
A static block
B static block
A not static blockB@a90653
A constructor
B not static block
B constructor
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。