12/08/2018, 17:19

Memory Management in Swift - Quản lý bộ nhớ trong Swift (Phần 1)

Đối với một dev việc tối ưa bộ nhớ Ram là cực kỳ quan trọng. Mà để tối ưu được bộ nhớ của Ram , chúng ta nên hiểu về cớ chế quản lý bộ nhớ (memory management) trong swift. Có 3 nơi để phân bổ bộ nhớ: Static memory - Bộ nhớ tĩnh - Không bao giờ thay đổi khi app chạy Stack ...

Đối với một dev việc tối ưa bộ nhớ Ram là cực kỳ quan trọng. Mà để tối ưu được bộ nhớ của Ram, chúng ta nên hiểu về cớ chế quản lý bộ nhớ (memory management) trong swift.

Có 3 nơi để phân bổ bộ nhớ:

  • Static memory - Bộ nhớ tĩnh - Không bao giờ thay đổi khi app chạy
  • Stack allocated memory - Phân bổ vùng nhớ theo ngăn xếp - Kiểu LIFO
  • Heap allocated memory - Phân bổ vùng nhớ động - Cớ chế ARC

Stack allocated memory

  • Mỗi một thread sẽ có một stack riêng.
  • Các Value type (kiểu giá trị) và tên biến, func sẽ được lưu vào stack . Việc giải phóng bộ nhớ sẽ được diễn ra tự động.
  • Về cơ bản stack lưu trữ dữ liệu ít hơn hẳn heap.

Heap allocated memory

  • Chỉ có một heap cho một app
  • Các property, instance của Reference type (kiểu tham chiếu) và sự liên kết giữa các object sẽ được lưu vào heap. Bộ nhớ sẽ tồn tại đến khi reference count = 0, programmer có thể thay đổi số reference count
  • Bộ nhớ của heap có thể nới rộng trong quá trình chạy app.
  • Sự khác biệt giữa swift và các ngôn ngữ khác chính là tại đây, với cơ chế ARC.

Tham khảo: https://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap

Ví dụ


Hình 1: Khi khai báo biến kiểu Int nên là Value type, được lưu trong stack

Hình 2: Khi gán b = a , thì giá trị của a sẽ được coppy và thay vào ô nhớ của b

Hình 1: Object girl đang chứa địa trỉ 5b2x... tham chiếu đến property chứa tại heap, có giá trị "mai".

Hình 2: Khi ta thay đổi girl.name = "linh", việc này diễn ra trực tiếp trên ô nhớ tại heap, địa trỉ tham chiếu đến ô nhớ không đổi.

Hình 3: Object girls chứa địa trỉ x90y... tham chiếu đến một ô nhớ khác trong heap, ô nhớ này có property là"lan".

Hình 4: Khi ta thay đổi girls = girl, tức là lúc này địa trỉ tham chiếu đến ô nhớ đã bị thay đổi. Cả girls và girl cùng tham chiếu đến ô nhớ có địa trỉ 5b2x...

Tham khảo: https://medium.com/@itchyankles/memory-management-in-rust-and-swift-8ecda3cdf5b7

Từ đây trở lên, swift tự động xử lý. Nên nếu bạn không hiểu thì cũng không sao cả. Điều bạn nên chú tâm chính là cơ chế ARC. Vì trong quá trình viết code nếu không cẩn thận, rất dễ dính phải trường hợp rò rỉ bộ nhớ - Leaking memory

Vậy còn ô nhớ có địa trỉ x90y... thì sao?

Lúc này không có ai trỏ đến nó, Reference count = 0, ô nhớ tự động bị giải phóng. Đó chính là cơ chế ARC.

ARC là cơ chế quản lý bộ nhớ trong swift, tự động đếm số lượng reference count và giải phóng bộ nhớ khi reference count = 0.

Ở ví dụ trên, số tham chiếu, liên kết hay gọi là Reference count đến ô chứa x90y... bằng 0, nên ô nhớ được giải phóng. Lúc này để kiểm tra ô nhớ đã được giải phóng hay chưa. Swift cung cấp thêm hàm deinit, hàm này sẽ được chạy trước khi ô nhớ được giải phóng. Bởi vậy trong class mới có hàm deinit còn struct thì không.

  • Mặc đinh một tham chiếu sẽ là strong - liên kết mạnh
  • Còn như này sẽ là weak - liên kết yếu.

Weak để làm gì vậy, nó khác gì so với strong. Để hiểu được chúng ta cùng xem một ví dụ rất hay của anh Thắng: https://github.com/vietanhpcd/RetainCycle

Ở ví vụ này các bạn cứ thử thay đổi 2 object trên thành strong hoặc weak, di chuyển qua lại giữa các màn, tại sao có lúc chạy vào hàm deinit, lúc lại không vậy? Ở phần 2 mình sẽ giải thích điều này.

lưu ý : Object là một thể hiện của một class.

Vòng đời của một Object:

  • Cấp phát vùng nhớ
  • Hàm khởi tạo init
  • Sử dụng Object
  • Deinit
  • Huỷ vùng nhớ
0