1. 程式人生 > >記Java中有關記憶體的簡單認識

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

# 一、Java記憶體劃分 分為五個部分,可以參考這篇筆記簡單認識一下: [https://www.cnblogs.com/unleashed/p/13268027.html](https://www.cnblogs.com/unleashed/p/13268027.html) |**棧** |**堆** |**方法區** |**本地方法棧** |**暫存器** | |:----|:----|:----|:----|:----| --- # # 二、從陣列的記憶體說起 --- # 一個 **陣列的記憶體圖** **首先,我們有這樣一組程式碼:** ```java 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]); } } ``` **看這張圖:** ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171236933-1826653034.png) |**“.class”檔案裡面主要儲存的就是main方法,**
**而圖中過程就是 “進棧”的過程,並且為main方法開闢了一個新的空間。**

**繼續來看** | |:----| ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171259831-946170915.png) |**“int[] array” 左邊其實是堆當中陣列的地址值**
**所以“array”這個變數儲存的其實是陣列的地址值**
**然後根據地址進行尋找陣列** | |:----| ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171308439-1033619889.png) |**輸出的時候,會自動找到陣列所有相關資訊** | |:----| ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171316976-46619326.png) |**當程式執行到賦值語句時**
**根據陣列的地址值找到陣列**
**並且找到索引位置進行修改數值**
**然後列印輸出的時候,又會重複此前的步驟,進行定址,取值** | |:----| --- # # 兩個陣列的記憶體圖 ## 1、新建陣列的情況 如果在剛才的main方法中新增一個這樣的語句 ```java int[] array2 = new int[10]; ``` 此時,需要我們記住只要 **new** 了,它就會在堆當中 **開闢出一個新的空間** ,也可以說是 **新的記憶體空間** ## 2、傳遞地址 如果新增的是這種語句呢? ```java int[] array2 = array; ``` --- **此時,堆當中還是隻有那一個數組,只是將 array 的地址值傳遞給 array2 ,,因為它們的地址值相等,當給 array2 賦值時,更改的內容就是原來 array 裡面的內容,也就是 : 兩個引用指向同一個陣列的情況** # 三、來看物件的記憶體 # 一個物件的記憶體圖 **首先,還是得有一段程式碼** ```java public class student{ String name; String ssex; int age; public void study(){ System.out.println("正在學習。。。。"); } public void eat(){ System.out.println("正在吃飯。。。。"); } } ``` **既然是物件,那就還得有一段程式碼,來使用這個student類** ```java 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(); } } ``` **那就從圖看起來** ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171333696-648782980.png) |**java中執行程式,首先是從main方法開始執行的**
**所以它必須第一個進棧** | |:----| ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171341808-336632897.png) |**此處要 注意 !!!**
**當new Student()時**
**Student.class中的成員方法地址值會儲存在堆當中**
**所以要記住,對於引用型別,都是地址在傳遞** | |:----| ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171349008-268467186.png) |**所謂的stu.name**
**就是在呼叫成員變數,所以通過地址值來進行定址**
**找到之後就進行更改**
**比如後面的語句**
**stu.name = "小杜" ;** | |:----| ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171356080-1073627511.png) |**物件.成員方法**
**通過地址值找到所要找的內容**
**然後開始進棧**
**當方法執行完畢後就會出現** **“彈棧”**
**然後執行下一條語句**
**在我們這段程式碼中,下一條語句還是呼叫成員方法**
**所以study方法執行玩之後就會被彈出**
**進行下一條指令**
**呼叫eat方法** | |:----| ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171403601-67231354.png) --- # # 兩個物件使用同一個方法時的記憶體圖 ```java 比如: Student stu = new Student(); Student stu2 = new Student(); …… ``` **都是指向方法區的同一塊方法的同一塊地址空間** --- # # 兩個引用指向同一個物件的記憶體圖 ```java Student stu = new Student(); Student stu2 = stu; …… ``` **尋找stu的地址值,然後根據stu的地址值進行呼叫方法** --- # 使用物件型別作為方法的引數 ```java 比如程式碼中有這麼兩三行 public static void method(Student stu){ System.out.println(stu.eat); …… } ``` **當一個物件作為方法的引數時,傳遞到方法中時,實際傳遞進去的是物件的地址值** --- # 使用物件型別作為方法的返回值 ```java public static Student eat(){ Student stu =new Student(); stu.study(); stu.name = "小杜"; return stu; } ``` **當使用一個物件型別作為方法的返回值時** **返回值其實就是物件的地址值** --- # 四、字串常量池 字串常量池:程式當中直接寫上的雙引號字串,就在字串常量池當中 所以: **對於基本型別來說,== 比較的是數值** **對於引用型別來說 ,== 比較的是地址值** **因為內容不可變性,所以可以共享的** **而且字串的效果相當於char[]陣列,但是底層原理是byte[]陣列,所以它會在儲存的過程中自動轉換成byte[]陣列** **借用一張網上的圖** ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171420205-1010951063.png) ## 順便提一下static關鍵字 **根據類名稱訪問靜態成員變數的時候,全程和物件是沒有關係的,只和類有關係。** --- # 五、繼承中的記憶體圖 ***圖片來源網路:*** ![](https://img2020.cnblogs.com/blog/2031154/202008/2031154-20200805171427556-1883359113.png) **也就是父類空間優先於子類物件的產生,在每次建立子類物件時,先初始化父類空間,再建立子類物件本