Tối ưu Memory trong Unity (Phần 1)

  • Tối ưu Memory (bộ nhớ) trong Unity là 1 phần quan trọng giúp Game tránh được các lỗi ANR và Crash.
  • Đa phần lỗi ANR là do Memory không tối ưu, bị tràn bộ nhớ RAM, hoặc các tiến trình bị chờ đợi quá lâu.
  • Chính vì vậy để tối ưu được ta cần hiểu gốc rễ việc Unity sử dụng các bộ nhớ như thế nào, cách tổ chức và lưu trữ ra sao.

1. Tổng Quan Về Memory trong Unity

Unity quản lý bộ nhớ chủ yếu dựa trên hai loại vực bộ nhớ:

  • Stack Memory:
    • Là khu vực bộ nhớ nhanh, được sử dụng để lưu trữ các biến local và tham chiếu tới đối tượng trong heap.
    • Dữ liệu trong stack sẽ được giải phóng tự động khi ra khỏi phạm vi của hàm.
  • Heap Memory:
    • Là khu vực dùng để lưu trữ các đối tượng được khởi tạo bằng new hoặc tham chiếu tới.
    • Việc quản lý bộ nhớ trong heap đòi hỏi được giám sát và giải phóng bởi Garbage Collector (GC).

Chi tiết kiến thức về Stack Heap: xem tại đây


2. Garbage Collector (GC) trong Unity

Garbage Collector (GC) là cơ chế quản lý bộ nhớ tự động trong Unity dựa trên .NET Runtime. GC sẽ giám sát heap để giải phóng bộ nhớ của các đối tượng không còn được tham chiếu.

2.1. Hoạt động cơ bản của GC

  1. Dán nhãn (“Mark Phase”):
    • GC dò tìm tất cả các đối tượng đang được tham chiếu trong heap.
    • Các đối tượng không còn tham chiếu sẽ được dán nhãn là “không còn sử dụng”.
  2. Dọn dẹp (“Sweep Phase”):
    • GC giải phóng bộ nhớ của các đối tượng không còn sử dụng.
  3. Di chuyển bộ nhớ (“Compaction Phase”):
    • GC sắp xếp lại bộ nhớ để tối ưu hoá việc truy cập.

2.2. Ảnh hưởng của GC tới Unity

  • GC có thể gây ra “GC Spike” (độ trễ chễ tạm thời) khi thu gom bộ nhớ, ảnh hưởng tới FPS.
  • Việc tạo nhiều đối tượng tạm thời (temporary objects) có thể làm heap nhanh chóng bão hòa.

3. Khởi Tạo Đối Tượng và Quản Lý Bộ Nhớ

3.1. Cách Unity Lưu Đối Tượng

  • Đối tượng value type (e.g., int, float, struct):
    • Lưu trong stack memory.
    • Tự động giải phóng khi ra khỏi scope.
  • Đối tượng reference type (e.g., class, array):
    • Lưu trong heap memory.
    • Cần GC giải phóng khi không còn được tham chiếu.

3.2. Tối ưu hoá khởi tạo đối tượng

  • Sử dụng Object Pooling:
    • Lặp lại các đối tượng thay vì tạo mới.
    • Giảm số lượng đối tượng tạm thời và tần suất GC.
  • Tránh tạo đối tượng trong các vòng lặp lần:
    • Giảm thiểu heap fragmentation (Phân mảnh bộ nhớ).
  • Dụng Struct khi thích hợp:
    • Để giảm thiệu việc phải quản lý heap.

3.3. Tránh GC Spike

  • Sử dụng các API như GC.Collect() cẩn thận:
    • Chỉ gọi khi bạn biết GC không ảnh hưởng tới gameplay.
  • Theo dõi bộ nhớ bằng Unity Profiler:
    • Xác định nguyên nhân sinh ra rác và tối ưu hoá code.

4. Kết Luận

  • Garbage Collector (GC) là một phần quan trọng trong quản lý bộ nhớ Unity, nhưng có thể gây ảnh hưởng tới hiệu năng nếu không được quản lý hợp lý.
  • Chúng ta cần viết code để làm sao GC phải làm việc ít nhất, không bị chiếm dụng tài nguyên của hệ thống.
  • Việc hiểu rõ cơ chế quản lý bộ nhớ và tối ưu hoá việc khởi tạo đối tượng là yếu tố then chốt giúp cải thiện hiệu suất của game.
  • GC có thể gây ra ANR nếu nó hoạt động quá thường xuyên hoặc mất quá nhiều thời gian khi chạy. Nguyên nhân chính là do tạm dừng UI Thread, phân mảnh bộ nhớ Heap, hoặc việc ứng dụng tạo quá nhiều đối tượng không cần thiết. Để giảm thiểu rủi ro ANR, bạn cần tối ưu hóa việc sử dụng bộ nhớ, giảm áp lực lên GC, và chuyển các công việc nặng ra ngoài UI Thread.

Để lại một bình luận 0

Your email address will not be published. Required fields are marked *