Rust ownership và borrow checker: quản lý bộ nhớ an toàn không cần GC

Ownership là gì?

Rust là ngôn ngữ lập trình đầu tiên đưa ownership vào type system để quản lý bộ nhớ. Mỗi giá trị trong Rust có một owner duy nhất; khi owner ra khỏi phạm vi, giá trị bị dropped và bộ nhớ được giải phóng tự động — không cần garbage collector, không cần gọi free thủ công.

Ownership giải quyết ba lỗi bộ nhớ phổ biến: use-after-free, double free, data race. Nếu vi phạm bất kỳ quy tắc nào, chương trình sẽ không compile được — lỗi bộ nhớ được phát hiện lúc biên dịch chứ không lúc chạy.


Sơ đồ cấu trúc bộ nhớ Rust với String lưu trên stack (pointer, length, capacity) và nội dung trên heap

Ba quy tắc ownership (nhớ kỹ)

Theo tài liệu chính thức của Rust, ownership hoạt động dựa trên ba quy tắc cơ bản:

  • Mỗi giá trị có một owner duy nhất.
  • Tại một thời điểm chỉ có một owner cho mỗi giá trị.
  • Khi owner ra khỏi scope, giá trị bị dropped.

Ba quy tắc này đảm bảo compile-time safety mà không cần GC runtime.

Move semantics

Kiểu nằm trên stack (i32, let x = 5; let y = x;) → gán tạo copy. Kiểu dùng heap (String): let s1 = String::from("hello"); let s2 = s1;move. s1 không còn hợp lệ sau lệnh gán.

Lý do: nếu copy con trỏ mà vẫn để cả hai s1/s2 dùng chung thì sẽ xảy ra double free (giải phóng bộ nhớ 2 lần). Rust ngăn chuyện này ngay lúc biên dịch. Khi cố dùng s1 sau move, bạn sẽ thấy lỗi:

error[E0382]: borrow of moved value: `s1`

Muốn copy thật sự (heap) → dùng .clone() (trait Clone).


Minh họa move semantics trong Rust: s1 được move vào s2, s1 không còn hợp lệ

Borrowing và borrow checker

Borrow checker là bộ phận trình biên dịch, kiểm tra statically rằng các tham chiếu luôn trỏ tới object hợp lệ. Trong khi còn reference tồn tại, object không thể bị destroy.

Thay vì lấy ownership, bạn có thể mượn bằng cách tạo reference &T:

fn calculate_length(s: &String) -> usize { s.len() }

Vì reference không sở hữu, giá trị trỏ tới sẽ không bị dropped khi reference hết vòng đời.

Immutable vs Mutable borrows

Rust phân biệt hai loại reference:

  • Immutable reference &T: chỉ đọc.
  • Mutable reference &mut T: sửa được, cần let mut s = ....

Quy tắc quan trọng: nếu có một mutable reference đến giá trị, thì không được có bất kỳ reference nào khác đến giá trị đó cùng lúc. Hai lỗi phổ biến:

error[E0499]: cannot borrow `s` as mutable more than once at a time
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable

Lifetimes (vòng đời)

Mỗi reference trong Rust đều có một lifetime — phạm vi hợp lệ. Đa số implicit, chỉ annotate khi có nhiều khả năng. Mục đích chính: ngăn dangling references.

Lỗi điển hình khi reference trỏ tới giá trị đã ra khỏi scope:

error[E0106]: missing lifetime specifier
--> message: "does not live long enough"

Ownership ngăn bug bộ nhớ

Nhờ quy tắc compile-time, Rust ngăn được toàn bộ class lỗi bộ nhớ phổ biến:

  • No use-after-free: reference luôn bảo đảm trỏ tới giá trị hợp lệ.
  • No data races: “một mutable ref HOẶC nhiều immutable ref” — không có hai nơi cùng ghi/đọc-ghi mâu thuẫn.
  • No double free: owner duy nhất và move semantics chuyển quyền sở hữu.
  • No null reference: Rust không cho phép null, giảm lỗi “null pointer exception”.

So sánh với Garbage Collection

So sánh ba cách quản lý bộ nhớ:

Ngôn ngữ Cơ chế Ưu điểm Nhược điểm
Java, Go, Python, JS Garbage Collection Không cần lo bộ nhớ Runtime overhead, pause, không kiểm soát tốc độ
C, C++ Cấp phát thủ công Tốc độ tối đa Dễ lỗi (use-after-free, double free, leak)
Rust Ownership + Borrow Checker An toàn như GC, tốc độ như C, zero runtime overhead Học curve cao hơn

Rust quảng bá: “no runtime or garbage collector, blazingly fast and memory-efficient.”rust-lang.org

Kết luận

Ownership và borrow checker là trái tim của Rust. Chúng biến compiler thành cấu trúc bảo vệ bộ nhớ, cho phép lập trình viên viết code hiệu năng cao mà không phải hy sinh an toàn. Khi làm việc với Rust, hãy coi compiler như người đồng nghiệp nghiêm khắc — nó không bỏ qua lỗi, nhưng cũng không bao giờ gây bug lúc runtime.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Sơ đồ workflow migrate và sqlc trong CI/CD pipeline

Database migration an toàn với Golang golang-migrate sqlc Atlas so sánh

Tại sao cần database migration tool trong Golang Khi xây dựng ứng dụng production với Golang, việc quản lý thay đổi schema database là bài toán bắt buộc. Ba công…

Xem thêm

TypeScript 5.5: type inference cải tiến, decorators chuẩn hóa, isolated declarations

Giới thiệu TypeScript 5.5 mang đến những cải tiến đáng kể cho hệ thống kiểu dữ liệu, khiến mã nguồn an toàn hơn và dễ bảo trì hơn. Bài viết…

Xem thêm

So sánh các web framework Python phổ biến

Giới thiệu So sánh các web framework Python phổ biến là một trong những chủ đề nóng nhất trong thời gian qua. Bài viết này sẽ cung cấp một cái…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất