Stack và Heap trong Java


Stack và Heap trong Java
Đối với các lập trình viên, không chỉ hoàn thiện chương trình là đủ, chúng ta còn phải làm cho chương trình có hiệu suất tốt hơn: làm chương trình chạy thời gian ngắn hơn, tốt ít bộ nhớ hơn. Vấn đề về bộ nhớ chính là một bài toán hiệu suất mà các nhà lập trình phải giải quyết nó một cách tối ưu nhất. Để giải quyết về vấn đề này, chúng ta cần phải hiểu rõ về bộ nhớ trên máy tính, đặc biệt là việc sử dụng bộ nhớ của nó.
Ô nhớ hiểu đơn giản là một đơn vị để lưu trữ dữ liệu. Tập hợp nhiều ô nhớ được gọi là bộ nhớ (hoặc vùng bộ nhớ). Trong Java, vì là một ngôn ngữ ra đời cải tiến hơn so với các ngôn ngữ trước, nên việc phân chia vùng nhớ và xử lý chúng không đơn giản chỉ xoay quanh về khái niệm bộ nhớ.
Bộ nhớ trong Java được chia làm 2 vùng: StackHeap.
Stack được xem là vùng bộ nhớ để thực thi luồng. Chúng lưu trữ các biến cục bộ, các tham số của phương thức. Chúng hoạt động như tên gọi của nó (Stack – chồng chất), biến đầu tiên sẽ nằm ở dưới cùng, các biến sau sẽ chồng lên biến trước và cứ thế lên trên cùng.
Heap là bộ nhớ để lưu trữ các đối tượng thực sự. Các object khi khởi tạo thì bộ nhớ của nó sẽ nằm trong Heap, còn bản thân nó là một địa chỉ lưu ở Stack và truy cập đến biến trong Heap. Ví dụ ta có Dog a = new Dog(), thì a mang giá trị là địa chỉ đi đến bộ nhớ thực sự của nó, nơi mà các thuộc tính được lưu bên trong nó.
Để hiểu rõ hơn cách StackHeap hoạt động, ta sẽ làm ví dụ như sau (vừa nhìn hình vừa đọc tiếp nhé):



Chúng ta tạo ra 1 class Dog, và một hàm main dùng để xuất ra name của class Dog. Ở đây, khi hàm main chạy, 1 luồng sinh ra, khi các biến khởi tạo trong luồng này, nó sẽ lưu trong Stack. Quy trình chạy theo các bước
1.     Ban đầu, chúng ta khai báo 1 biến t là kiểu số nguyên, biến này sẽ tạo trong bộ nhớ Stack.
2.     Tiếp đó, chúng ta khai báo 1 biến aDog kiểu Dog, biến này sẽ được lưu trong bộ nhớ Stack.
3.     Khi chúng ta khởi tạo bằng toán tử new và truyền tham số vào, lúc này các bộ nhớ trong vùng Heap sẽ cung cấp cho đối tượng này, cụ thể là cung cấp cho các thuộc tính của đối tượng này. Khi chạy hết hàm Constructor, các giá trị sẽ đưa vào các thuộc tính trên. Cuối cùng, biến aDog sẽ lưu trữ địa chỉ trỏ tới vùng nhớ đó.
4.     Bắt đầu thực hiện gọi hàm viewName() và truyền tham số aDog vào.
5.     Trong viewName(), biến thisDog được sinh ra tại Stack, và được truyền địa chỉ từ aDog vào, nên cả aDog và thisDog đều mang cùng 1 địa chỉ trỏ tới Object đã khởi tạo trước đó.
6.     Biến String được khai báo, và nó cũng lưu địa chỉ tại Stack, trỏ đến vị trí chứa dữ liệu là name của thisDog.
Vì String là một dạng dữ liệu dặc biệt, không phải kiểu nguyên thủy, và cách tổ chức bộ nhớ cũng khác so với các kiểu dữ liệu khác, nên mình chỉ nói một cách đơn giản nhất thôi
7.     Class System gọi hàm out.print() ra làm việc. Hàm trên làm việc và xuất ra Console name của thisDog.
            Tuy có vẻ khó hiểu nhưng thực sự thì khó hiểu thật *cười. Có một số khuất mắt mình vẫn không thể giải đáp được, ví dụ như là int t khi chưa gán giá trị thì có khởi tạo vùng nhớ hay không, và nguyên tắc sử dụng bộ nhớ của String. Tuy nhiên, vấn đề cơ bản về StackHeap cũng đã được giải quyết ổn thỏa. Phù!
Nội dung bài viết thuộc về Lê Công Diễn.

Người viết: Lê Công Diễn
Mang đi nhớ ghi nguồn

Nhận xét

Bài đăng phổ biến từ blog này

Deploy project Springboot MIỄN PHÍ sử dụng Render

Ứng dụng Mã hóa bất đối xứng (Asymmetric cryptography) vào Chữ ký số (Digital Signature)

API và HTTP - Một số khái niệm cơ bản cần biết về Web (Phần 2)