記Java中有關記憶體的簡單認識

一、Java記憶體劃分

分為五個部分,可以參考這篇筆記簡單認識一下:

//www.cnblogs.com/unleashed/p/13268027.html

方法區 本地方法棧 暫存器

二、從數組的記憶體說起


一個 數組的記憶體圖

首先,我們有這樣一組程式碼:

1 public class HelloWorld{ 
2  public static void main(String[] args){ 
3     int[] array = new int[2]; 
4     System.out.println(array); 
5     System.out.println(array[0]); 
6     System.out.println(array[1]);     
7     array[0]= 1; 
8     array[1]= 2; 
9     System.out.println(array); 
10     System.out.println(array[0]); 
11    System.out.println(array[1]); 
  } 
} 

看這張圖:

「.class」文件裡面主要保存的就是main方法,
而圖中過程就是 「進棧」的過程,並且為main方法開闢了一個新的空間。

繼續來看

「int[] array」 左邊其實是堆當中數組的地址值
所以「array」這個變數存儲的其實是數組的地址值
然後根據地址進行尋找數組

輸出的時候,會自動找到數組所有相關資訊

當程式執行到賦值語句時
根據數組的地址值找到數組
並且找到索引位置進行修改數值
然後列印輸出的時候,又會重複此前的步驟,進行定址,取值

兩個數組的記憶體圖

1、新建數組的情況

如果在剛才的main方法中添加一個這樣的語句

int[] array2 = new int[10]; 

此時,需要我們記住只要 new 了,它就會在堆當中 開闢出一個新的空間 ,也可以說是 新的記憶體空間

2、傳遞地址

如果添加的是這種語句呢?

int[] array2 = array; 

此時,堆當中還是只有那一個數組,只是將 array 的地址值傳遞給 array2 ,,因為它們的地址值相等,當給 array2 賦值時,更改的內容就是原來 array 裡面的內容,也就是 : 兩個引用指向同一個數組的情況

三、來看對象的記憶體

一個對象的記憶體圖

首先,還是得有一段程式碼

public class student{ 
  String name; 
  String ssex; 
  int age; 
  public void study(){ 
    System.out.println("正在學習。。。。"); 
  } 
  public void eat(){ 
    System.out.println("正在吃飯。。。。"); 
  } 
} 

既然是對象,那就還得有一段程式碼,來使用這個student類

 public class TestStudent{ 
   public static void main(String[] args){ 
     Student stu = new Student(); 
     System.out.println(stu.name); 
     System.out.println(stu.ssex); 
     System.out.println(stu.age); 
      
     stu.name = "小杜"; 
     stu.age = 20; 
     stu.ssex = "男"; 
      
     System.out.println(stu.name); 
     System.out.println(stu.ssex); 
     System.out.println(stu.age); 
    stu.study(); 
    stu.eat(); 
   } 
 } 

那就從圖看起來

java中執行程式,首先是從main方法開始執行的
所以它必須第一個進棧

此處要 注意 !!!
當new Student()時
Student.class中的成員方法地址值會保存在堆當中
所以要記住,對於引用類型,都是地址在傳遞

所謂的stu.name
就是在調用成員變數,所以通過地址值來進行定址
找到之後就進行更改
比如後面的語句
stu.name = “小杜” ;

對象.成員方法
通過地址值找到所要找的內容
然後開始進棧
當方法執行完畢後就會出現 「彈棧」
然後執行下一條語句
在我們這段程式碼中,下一條語句還是調用成員方法
所以study方法執行玩之後就會被彈出
進行下一條指令
調用eat方法


兩個對象使用同一個方法時的記憶體圖

比如: 
  Student stu = new Student(); 
  Student stu2 = new Student(); 
  …… 

都是指向方法區的同一塊方法的同一塊地址空間


兩個引用指向同一個對象的記憶體圖

Student stu = new Student(); 
Student stu2 = stu; 
…… 

尋找stu的地址值,然後根據stu的地址值進行調用方法


使用對象類型作為方法的參數

比如程式碼中有這麼兩三行 
  public static void method(Student stu){ 
    System.out.println(stu.eat); 
    …… 
  } 

當一個對象作為方法的參數時,傳遞到方法中時,實際傳遞進去的是對象的地址值


使用對象類型作為方法的返回值

public static Student eat(){ 
  Student stu =new Student(); 
  stu.study(); 
  stu.name = "小杜"; 
  return stu; 
} 

當使用一個對象類型作為方法的返回值時
返回值其實就是對象的地址值


四、字元串常量池

字元串常量池:程式當中直接寫上的雙引號字元串,就在字元串常量池當中

所以:

對於基本類型來說,== 比較的是數值

對於引用類型來說 ,== 比較的是地址值

因為內容不可變性,所以可以共享的

而且字元串的效果相當於char[]數組,但是底層原理是byte[]數組,所以它會在存儲的過程中自動轉換成byte[]數組

借用一張網上的圖

順便提一下static關鍵字

根據類名稱訪問靜態成員變數的時候,全程和對象是沒有關係的,只和類有關係。


五、繼承中的記憶體圖

圖片來源網路:

也就是父類空間優先於子類對象的產生,在每次創建子類對象時,先初始化父類空間,再創建子類對象本身。

Tags: