OOP Bài 5: Quá trình khởi tạo đối tượng (Instantiation) trong bộ nhớ
1. Phân định ranh giới: Stack và Heap
Trước khi Object ra đời, chúng ta cần hiểu bộ nhớ RAM cấp phát cho chương trình được chia làm hai khu vực chính:
- Bộ nhớ Stack (Ngăn xếp): Tốc độ cực nhanh, quản lý tự động, dung lượng nhỏ. Dùng để lưu các biến cục bộ, các lệnh gọi hàm và địa chỉ tham chiếu (con trỏ).
- Bộ nhớ Heap (Đống): Tốc độ chậm hơn, quản lý động, dung lượng lớn. Đây chính là "vùng đất" cấp phát không gian cho các Đối tượng (Objects) thực tế.
(Lưu ý: Ở các ngôn ngữ như C++, bạn có quyền quyết định tạo Object trên Stack hay Heap. Nhưng ở PHP, Java, hay C#, Object sử dụng từ khóa
newmặc định luôn nằm trên Heap. Riêng Go dùng Escape Analysis để tự định đoạt).
2. Quá trình Instantiation diễn ra qua 3 bước cốt lõi
Hãy lấy một dòng code đơn giản làm ví dụ:
$myTicket = new SmartCard("TICK_01", 50000);
Dưới nắp capo, hệ điều hành và Runtime/Virtual Machine sẽ làm 3 việc sau:
Bước 1: Cấp phát bộ nhớ trên Heap (Allocation)
Hệ thống sẽ quét bản thiết kế Class SmartCard để tính toán xem cần bao nhiêu byte để chứa toàn bộ Thuộc tính của nó.
- Tại sao chỉ tính dung lượng Thuộc tính? Vì các Phương thức (Methods) là logic tĩnh, chúng không được copy ra cho từng Object. Hàng triệu Object
SmartCardsẽ dùng chung một bản lưu mã lệnh của hàmtapIn()ở một vùng nhớ khác (Code Segment/Method Area). - Hệ thống tìm một khoảng trống đủ lớn trên Heap, "khoanh vùng" lại và cấp phát cho Object mới. Lúc này, Object là một vùng RAM thô chứa rác dữ liệu.
Bước 2: Khởi tạo dữ liệu (Initialization & Constructor)
Ngay sau khi có đất (RAM), chương trình sẽ dọn dẹp vùng nhớ đó.
- Nó gán các giá trị mặc định (như
null,0,false) cho các thuộc tính. - Tiếp theo, hàm khởi tạo Constructor (
__constructtrong PHP) được gọi. Dữ liệu thực tế ("TICK_01",50000) được bơm vào vùng nhớ này, biến nó thành một Object có trạng thái hoàn chỉnh.
Bước 3: Trả về tham chiếu (Reference Assignment)
Object đã nằm yên vị trên Heap, nhưng làm sao code của chúng ta tương tác được với nó? Hệ thống sẽ lấy địa chỉ vùng nhớ của Object trên Heap (ví dụ: 0x7fff5a8b), và gán địa chỉ đó cho biến $myTicket.
- Biến
$myTicketthực chất nằm trên Stack. - Nó không chứa bản thân Object, nó chỉ đóng vai trò là chiếc "điều khiển từ xa" (Reference/Pointer) trỏ thẳng đến cục dữ liệu trên Heap.
3. Sơ đồ minh họa bộ nhớ
STACK MEMORY HEAP MEMORY
(Nơi chứa biến điều khiển) (Nơi chứa thực thể Object)
+------------------------+ +-------------------------+
| | (Trỏ đến) | Object: SmartCard |
| $myTicket = 0x7fff5a8b |===============>| - cardNumber: "TICK_01" |
| | | - balance: 50000 |
+------------------------+ | - status: 'active' |
+-------------------------+
4. Hệ quả thực chiến: Hiện tượng "Aliasing" (Bí danh)
Vì biến $myTicket chỉ là con trỏ, điều gì xảy ra nếu bạn viết dòng code sau?
$ticketCopy = $myTicket;
Trong kiến trúc hệ thống, dòng code này không hề tạo ra một Object mới. Nó chỉ tạo ra một chiếc "điều khiển từ xa" thứ hai nằm trên Stack, nhưng cả hai điều khiển đều trỏ về cùng một Object trên Heap.
Nếu gọi $ticketCopy->topUp(10000);, số dư của $myTicket cũng sẽ tăng theo, vì thực chất chúng là một. Đây là tính năng (truyền tham chiếu) nhưng cũng là nguồn cơn của vô số bug logic về tính toàn vẹn dữ liệu nếu không kiểm soát chặt chẽ.
All rights reserved