Trong các ứng dụng quy mô lớn, việc không hiểu cách bộ nhớ vận hành sẽ dẫn đến hiện tượng "tràn bộ nhớ" (Memory Leaks), khiến trình duyệt chậm dần và cuối cùng là crash.
1. Phân bổ bộ nhớ: Stack vs Heap
JavaScript chia bộ nhớ thành hai khu vực chính:
Stack (Ngăn xếp)
- Dành cho các dữ liệu nguyên thủy (String, Number, Boolean, null, undefined) và các biến tham chiếu (Pointer).
- Kích thước cố định, truy cập cực nhanh.
- Tự động giải phóng khi hàm kết thúc (LIFO).
Heap (Đống)
- Dành cho Objects, Arrays, Functions.
- Kích thước động, không giới hạn rõ rệt.
- Truy cập chậm hơn Stack vì phải thông qua tham chiếu.
- Cần Garbage Collector để giải phóng.

2. Cơ chế Garbage Collection (GC)
V8 Engine sử dụng thuật toán Mark-and-Sweep:
- Mark: GC đi từ "roots" (biến toàn cục, stack hiện tại) và đánh dấu tất cả các object có thể truy cập được.
- Sweep: Tất cả các object không được đánh dấu sẽ bị coi là rác và bị xóa khỏi bộ nhớ.
Lưu ý Senior: Khác với C++, bạn không chủ động xóa object, nhưng bạn phải "ngắt kết nối" (nullify) để GC có thể quét được.
3. Các loại Memory Leaks phổ biến
A. Biến toàn cục (Global Variables)
Nếu bạn vô tình tạo biến toàn cục, nó sẽ tồn tại mãi mãi trong Window object và không bao giờ bị GC thu hồi.
function leak() {
this.complexData = new Array(1000000); // Gán vào window nếu không dùng strict mode
}B. Quên gỡ bỏ Event Listeners
Khi bạn xóa một DOM element nhưng không gỡ bỏ event listener đính kèm, closure của listener đó vẫn giữ tham chiếu đến element, khiến element không bị xóa hoàn toàn.
C. Cấu trúc dữ liệu Map/Set
Sử dụng Map hoặc Set với object làm key sẽ giữ tham chiếu mạnh. Hãy dùng WeakMap hoặc WeakSet để cho phép GC thu hồi object khi không còn biến nào khác tham chiếu đến chúng.
4. Kỹ thuật Optimize bộ nhớ
- Object Pooling: Thay vì tạo mới hàng nghìn object (ví dụ trong Game hoặc Chart phức tạp), hãy tái sử dụng các object cũ.
- Hidden Classes: Không nên thay đổi cấu trúc của object (thêm/bớt thuộc tính) sau khi khởi tạo. V8 tạo ra "Hidden Classes" để tối ưu truy cập, việc thay đổi cấu trúc sẽ phá vỡ tối ưu này.
// Tốt: Cấu trúc cố định
function Point(x, y) {
this.x = x;
this.y = y;
}
const p1 = new Point(1, 2);
const p2 = new Point(3, 4); // Cùng Hidden Class
// Xấu: Cấu trúc thay đổi
p1.z = 5; // V8 phải tạo Hidden Class mới cho p1, p2 vẫn dùng class cũ.Hiểu về bộ nhớ giúp bạn viết code không chỉ chạy được, mà còn chạy mượt mà trong thời gian dài trên các thiết bị cấu hình yếu.