1. Stack memory allocation
Stack memory allocation: Việc cấp phát này xảy ra trên các khối bộ nhớ liền kề. Chúng ta gọi nó là Stack memory allocation vì việc cấp phát xảy ra trong ngăn xếp lệnh gọi hàm. Kích thước của bộ nhớ được cấp phát đã được trình biên dịch biết và bất cứ khi nào một hàm được gọi, các biến của nó sẽ nhận được bộ nhớ được cấp phát trên ngăn xếp. Và bất cứ khi nào gọi hàm kết thúc, bộ nhớ cho các biến sẽ được hủy cấp phát. Tất cả điều này xảy ra bằng cách sử dụng một số quy trình được xác định trước trong trình biên dịch. Lập trình viên không phải lo lắng về việc cấp phát bộ nhớ và hủy cấp phát các biến ngăn xếp. Loại cấp phát bộ nhớ này còn được gọi là Cấp phát bộ nhớ tạm thời bởi vì ngay sau khi phương thức kết thúc việc thực thi, tất cả dữ liệu thuộc về phương thức đó sẽ tự động thoát ra khỏi ngăn xếp. Có nghĩa là, bất kỳ giá trị nào được lưu trữ trong lược đồ bộ nhớ ngăn xếp đều có thể truy cập được miễn là phương thức chưa hoàn thành việc thực thi và hiện ở trạng thái đang chạy.
Những điểm chính của bộ nhớ stack:
- Nó cấp phát bộ nhớ tạm thời trong đó các thành viên dữ liệu chỉ có thể truy cập được nếu phương thức chứa chúng hiện đang chạy.
- Nó tự động cấp phát hoặc hủy cấp phát bộ nhớ ngay sau khi phương thức tương ứng hoàn thành việc thực thi.
- Chúng ta nhận được nếu bộ nhớ ngăn xếp được lấp đầy hoàn toàn.
- Cấp phát bộ nhớ stack được coi là an toàn hơn so với cấp phát bộ nhớ heap vì dữ liệu được lưu trữ chỉ có thể được truy cập bởi luồng chủ của nó.
- Cấp phát và thu hồi cấp phát bộ nhớ nhanh hơn so với cấp phát bộ nhớ Heap.
- Bộ nhớ stack được cấp phát bộ nhớ lưu trữ nhỏ hơn so với bộ nhớ Heap.
Tất cả các biện trên sẽ được cấp pháp bộ nhớ trong bộ nhớ stack.
2. Heap memory allocation
Bộ nhớ được cấp phát trong quá trình thực thi các lệnh do người lập trình viết. Lưu ý rằng tên heap không liên quan gì đến cấu trúc dữ liệu heap. Nó được gọi là heap vì nó là một không gian bộ nhớ có sẵn cho các lập trình viên để cấp phát và thu hồi cấp phát. Mỗi khi chúng ta tạo một đối tượng, nó luôn tạo ra trong Heap-space và thông tin tham chiếu đến các đối tượng này luôn được lưu trữ trong bộ nhớ stack. Phân bổ bộ nhớ Heap không an toàn như phân bổ bộ nhớ Stack vì dữ liệu được lưu trữ trong vùng này có thể truy cập hoặc hiển thị cho tất cả các chuỗi. Nếu một lập trình viên không xử lý tốt bộ nhớ này, thì chương trình có thể bị thiếu bộ nhớ.
Việc cấp phát bộ nhớ Heap được chia thành ba loại. Ba loại này giúp chúng ta sắp xếp thứ tự ưu tiên dữ liệu (đối tượng) sẽ được lưu trữ trong bộ nhớ Heap hoặc trong quá trình thu gom rác (quá trình xác định và loại bỏ các Object không được sử dụng (unreferenced) khỏi bộ nhớ Heap) bao gồm:
- Young Generation: Phần bộ nhớ nơi tất cả dữ liệu (đối tượng) mới được tạo ra để phân bổ vùng và bất cứ khi nào bộ nhớ này được lấp đầy hoàn toàn thì phần còn lại của dữ liệu sẽ được lưu trữ trong bộ sưu tập Rác.
- Old or Tenured Generation: Phần của bộ nhớ Heap chứa các đối tượng dữ liệu cũ hơn không được sử dụng thường xuyên hoặc không được sử dụng nữa sẽ được đặt.
- Permanent Generation: Đây là phần của bộ nhớ Heap chứa siêu dữ liệu của JVM cho các lớp thời gian chạy và các phương thức ứng dụng.
Những điểm chính của hepa memory allocation:
- Chúng ta nhận được thông báo lỗi tương ứng nếu Heap-space đã đầy hoàn toàn.
- Việc cấp phát bộ nhớ này khác với bộ nhớ stack, ở đây không cung cấp tính năng tự động thu hồi bộ nhớ. Chúng ta cần sử dụng quá trình xác định và loại bỏ rác để loại bỏ các đối tượng cũ không sử dụng để sử dụng bộ nhớ một cách hiệu quả.
- Thời gian xử lý (Thời gian truy cập) của bộ nhớ này khá chậm so với bộ nhớ stack.
- Bộ nhớ Heap cũng không phải là một luồng an toàn như bộ nhớ stack vì dữ liệu được lưu trữ trong bộ nhớ Heap được hiển thị cho tất cả các luồng.
- Bộ nhớ đống có thể truy cập hoặc tồn tại miễn là toàn bộ ứng dụng chạy.
- bộ nhớ Heap được cấp phát bộ nhớ lưu trữ lớn hơn so với bộ nhớ stack.
Bộ nhớ này cho 10 kiểu dữ liệu interger được cấp phát trong Heap.
Ví dụ:
Trong ví dụ trên:
- Khi chúng ta bắt đầu thực thi chương trình có, tất cả các lớp thời gian chạy được lưu trữ trong không gian bộ nhớ Heap.
- Sau đó, chúng ta tìm thấy phương thức main() trong dòng tiếp theo được lưu trữ trong bộ nhớ stack cùng với tất cả các phương thức nguyên thủy (hoặc cục bộ) và biến tham chiếu Emp kiểu Emp_detail cũng sẽ được lưu trữ trong bộ nhớ stack và sẽ trỏ đến đối tượng tương ứng được lưu trữ trong bộ nhớ Heap.
- Sau đó, dòng tiếp theo sẽ gọi đến phương thức khởi tạo tham số Emp(int, String) từ main() và nó cũng sẽ cấp phát cho phần trên cùng của cùng một khối bộ nhớ Stack. Điều này sẽ lưu trữ:
- Đối tượng tham chiếu của đối tượng được gọi của bộ nhớ Stack.
- Giá trị nguyên thủy (kiểu dữ liệu nguyên thủy) int id trong bộ nhớ Stack.
- Biến tham chiếu của đối số String emp_name sẽ trỏ đến chuỗi thực từ nhóm chuỗi vào bộ nhớ heap.
- Sau đó, phương thức main sẽ lại gọi đến phương thức static Emp_detail(), phương thức này sẽ được thực hiện trong khối bộ nhớ Stack trên đầu khối bộ nhớ trước đó.
- Vì vậy, đối với đối tượng mới tạo Emp kiểu Emp_detail và tất cả các biến thể hiện sẽ được lưu trữ trong bộ nhớ heap.
Cụ thể như hình dưới: