Stack lưu biến local + tham chiếu, cấp riêng mỗi thread, tự giải phóng khi method kết thúc (LIFO). Heap lưu object thật, chia sẻ giữa mọi thread, do Garbage Collector dọn.
void demo() {
int x = 5; // x nằm trên STACK
Person p = new Person(); // tham chiếu p ở stack, object Person ở HEAP
} // hết method: x + p rời stack, object chờ GCVì sao tách: stack nhanh (chỉ dịch con trỏ) nhưng nhỏ + ngắn hạn theo method; heap lớn, sống lâu, nhưng cần GC nên chậm hơn.
Lưu ý:
- Đệ quy quá sâu → StackOverflowError (tràn stack).
- Quá nhiều object sống lâu → OutOfMemoryError: Java heap space (tràn heap).
- 2 biến cùng trỏ 1 object trên heap → sửa qua biến này, biến kia thấy đổi theo.
Chốt phỏng vấn: primitive + reference ở stack, object luôn ở heap. "Java pass-by-value" = copy cái reference, không copy object.
Stack holds local variables + references, is allocated per thread, and is freed automatically when a method returns (LIFO). Heap holds the actual objects, is shared across all threads, and is cleaned by the Garbage Collector.
void demo() {
int x = 5; // x lives on the STACK
Person p = new Person(); // reference p on the stack, Person object on the HEAP
} // method ends: x + p leave the stack, the object awaits GCWhy split: the stack is fast (just move a pointer) but small and method-scoped; the heap is large and long-lived but needs GC, so it is slower.
Pitfalls:
- Too-deep recursion → StackOverflowError.
- Too many long-lived objects → OutOfMemoryError: Java heap space.
- Two variables pointing to the same heap object → a change via one is visible through the other.
Interview takeaway: primitives + references on the stack, objects always on the heap. "Java is pass-by-value" = it copies the reference, not the object.