Bộ nhớ Heap và bộ nhớ Stack đều là một phần của JVM dùng để thực thi chương trình Java. Khi chương trình được thực thi JVM sẽ yêu cầu hệ điều hành cấp phát bộ nhớ trong Ram để chạy, JVM sẽ chia thành bộ nhớ Heap và bộ nhớ Stack để quản lý.
Mục Lục
Bộ nhớ Heap
Ở bài trước chúng ta đã biết bộ nhớ Heap dùng để lưu trữ tất cả các đối tượng được tạo ra trong quá trình thực thi ứng dụng (sử dụng toán tử new).
Objects trong bộ nhớ Heap đều được truy cập bởi mọi nơi trong ứng dụng, mọi threads khác nhau. Thời gian tồn tại của objects phụ thuộc vào GC (trình thu thập rác tự động). Các objects không được sử dụng trong Heap sẽ được GC loại bỏ và trả lại bộ nhớ cho Heap.
Dung lượng bộ nhớ của Heap phụ thuộc vào số lượng Objects sử dụng. Dung lượng bộ nhớ Heap thường lớn hơn dung lượng bộ nhớ Stack. Cơ chế quản lý của Heap chia ra làm hai loại Young-Generation và Old-Generation (tìm hiểu trong bài tiếp theo)
Bộ nhớ Stack
Bộ nhớ stack dùng để lưu các biến cục bộ trong hàm và lời gọi hàm ở runtime trong một thread java, theo từng luồng riêng biệt nhau và không được sử dụng lẫn nhau giữa các luồng khác nhau.
Các biến local bao gồm kiểu nguyên thuỷ (primitive) và kiểu tham chiếu tới đối tượng trong heap (reference) khai báo trong hàm, hoặc đối số được truyền vào hàm, thường có thời gian sống ngắn.
Hiểu đơn giản chỗ này nghĩa là tất cả những biến được khai báo hoặc truyền đối số trong một phương thức thì sẽ được cấp phát một vùng nhớ trong bộ nhớ stack theo luồng riêng. Khi hàm thực hiện xong thì khối bộ nhớ stack cho hàm sẽ bị xóa và giải phóng bộ nhớ trong stack.
Quy luật quản lý bộ nhớ trong stack: trong stack sử dụng quy luật LIFO (vào sau chết trước), nghĩa là: khối bộ nhớ được khởi tạo sau trong stack sẽ được giải phóng trước, khối bộ nhớ được khởi tạo trước trong stack sẽ được giải phóng sau.
Ví dụ minh họa
public class Car {
public static void main(String[] args) { // Line 1
int i = 1; // Line 2
Object obj = new Object(); // Line 3
Car car = new Car(); // Line 4
car.driver(obj); // Line 5
} // Line 6
private void driver(Object object) { // Line 7
String str = object.toString(); //// Line 8
System.out.println(str);
} // Line 9
}
Giải thích ý nghĩa
- Khi chạy chương trình thì một thread sẽ được khởi tạo và gọi hàm main() ở
Line 1
, lúc này một khối bộ nhớ cho hàm main() được khởi tạo trong stack. - ở
Line 2
một biến cục bộ kiểu primitive được khởi tạo, lúc này nó sẽ được lưu trong cùng khối bộ nhớ của hàm main() trong stack. - ở
Line 3
một đối tượng Object được khởi tạo, lúc này nó sẽ được lưu trong bộ nhớ heap, đồng thời biến tham chiếu của nó là obj được lưu vào khối bộ nhớ của hàm main() trong stack. - ở
Line 4
một đối tượng Car được khởi tạo, lúc này nó sẽ được lưu trong bộ nhớ heap, đồng thời biến tham chiếu car của nó được lưu vào khối bộ nhớ của hàm main() trong stack. - ở
Line 5
hàm driver() được gọi, lúc này một khối bộ nhớ cho hàm driver() được khởi tạo trong stack. - ở
Line 7
hàm driver() có một đối số kiểu Object, lúc này biến tham chiếu object sẽ được lưu trong khối bộ nhớ của hàm driver() trong stack. - ở
Line 8
một đối tượng cục bộ được khởi tạo, lúc này biến tham số str sẽ được lưu ở khối bộ nhớ hàm driver() và biến này tham chiếu tới đối tượng StringPool ở trong bộ nhớ Heap (chúng ta sẽ tìm hiểu StringPool ở các bài tiếp theo). - ở
Line 9
thì hàm driver() kết thúc, lúc này khối bộ nhớ stack cho hàm driver() sẽ được giải phóng. - hàm main() kết thúc ở
Line 6
nên khối bộ nhớ stack cho hàm main() cũng sẽ được giải phóng, vì nó tuân theo quy luật LIFO (vào sau chết trước) nên là khối bộ nhớ cho hàm driver() được khởi tạo sau sẽ giải phóng trước, sau đó đến hàm main() được khởi tạo trước nên giải phóng sau.
So sánh bộ nhớ Heap và Stack
Bộ nhớ Heap | Bộ nhớ Stack |
---|---|
Là bộ nhớ được sử dụng khi runtime, bất cứ khi nào đối tượng được khởi tạo trong chương trình thì nó sẽ được lưu trong bộ nhớ Heap (sử dụng toán tử new) | Là bộ nhớ dùng để lưu các biến cục bộ trong hàm và lời gọi hàm ở runtime trong một Thread java. Biến cục bộ bao gồm các loại: – biến loại nguyên thủy – biến loại tham chiếu tới đối tượng lưu trong Heap – biến loại đối số được truyền vào hàm – biến loại được khởi tạo trong thân hàm |
Thời gian sống phụ thuộc vào Garbage Collection, GC sẽ chạy trên bộ nhớ Heap để xoá các Object không được sử dụng nữa, nghĩa là object không được reference(tham chiếu) trong chương trình. | Thời gian sống ngắn, sau khi phương thức kết thúc |
các đối tượng lưu trong Heap được sử dụng bởi tất cả các nơi trong ứng dụng, bởi các thread khác nhau | dữ liệu trong stack chỉ được sử dụng trong cùng một thread, các thread khác nhau không sử dụng dữ liệu của nhau |
cơ chế quản lý của Heap phức tạp hơn stack, chia ra làm hai loại Young-Generation, Old-Generation | cơ chế quản lý của stack là LIFO (Last in first out, vào sau ra trước) |
Dung lượng Heap thường lớn hơn stack | Dung lượng stack thường nhỏ |
Dung lượng sử dụng của Heap sẽ tăng giảm phụ thuộc vào số lượng đối tượng được tạo trong heap. | Bất cứ khi nào gọi một hàm, thì một khối bộ nhớ stack cho hàm sẽ được khởi tạo, sau khi sử dụng xong thì khối bộ nhớ sẽ bị xóa, và giải phóng bộ nhớ cho stack |
Sử dụng -Xms và -Xmx để định nghĩa dung lượng bắt đầu và dung lượng tối đa của bộ nhớ heap | Dùng -Xss để định nghĩa dung lượng bộ nhớ stack. |
Truy cập bộ nhớ Heap chậm | Truy cập bộ nhớ Stack nhanh |
Khi Heap bị đầy chương trình sẽ phát sinh lỗi java.lang.OutOfMemoryError: Java Heap Space | Khi Stack bị đầy, chương trình phát sinh lỗi: java.lang.StackOverFlowError |
Xem thêm các bài viết liên quan dưới đây:
- Hướng dẫn cài đặt JDK 8 trên windows
- Phân biệt JDK JRE và JVM trong Java
- Quy ước đặt tên trong Java (Naming convention)
- Pass by value, Pass by reference trong java
- Từ khóa trong java và chức năng của nó (keywords)
- Kiểu dữ liệu trong java và tác dụng của nó
- Improve Java Performance: thủ thuật tối ưu [Phần 1]
- Biết sử dụng git cherry-pick để làm việc hiệu quả hơn
- Git stash giúp bạn trở nên chuyên nghiệp như thế nào?
- Git revert với git reset hoạt động như thế nào
- Build hệ thống Pub Sub dùng Hazelcast và Spring boot
- Build hệ thống Pub-Sub bằng Kafka+Spring boot (phần 3)
- Lập trình viên lúc rảnh rỗi thì nên làm gì?
- Câu chuyện phỏng vấn online mùa Covid
- Nói sao để được chào đón, làm thế nào để được ghi nhận
- Series tìm hiểu System Design
- Series tìm hiểu Hazelcast
- Series tìm hiểu lập trình java
- Series crack Intellij IDEA
- Series tìm hiểu Docker
- Series tìm hiểu Git
- Series tìm hiểu Kafka
- Series tìm hiểu ElasticSearch
- Series tìm hiểu Linux
- Series phỏng vấn kĩ sư phần mềm
- Series review sách