Quản lý bộ nhớ

Câu hỏi đầu tiên của hầu hết các nhà phát triển Java là cách quản lý bộ nhớ do J2ObjC triển khai, vì Java có tính năng thu thập rác và Objective-C không theo mặc định. iOS có hai phương pháp quản lý bộ nhớ: đếm tham chiếu và Đếm tham chiếu tự động (ARC).

J2ObjC tạo nhiều mã quản lý bộ nhớ, tuỳ thuộc vào phương thức được chọn. Dịch bằng tuỳ chọn -use-arc để tạo mã sử dụng ARC. Theo mặc định, trường này sử dụng phương pháp đếm tham chiếu thủ công.

Số lượng Tham chiếu

Phương thức tính tệp tham chiếu làm cho quyền sở hữu đối tượng trở nên rõ ràng. Một phương thức sẽ sở hữu một đối tượng khi tạo đối tượng đó cho đến khi giải phóng đối tượng đó. Khi nhận một đối tượng từ một phương thức khác, phương thức nhận sẽ giữ lại đối tượng nếu cần được tham chiếu sau khi phương thức này trả về. Khi không cần tham chiếu đến một đối tượng nữa, phương thức phải giải phóng đối tượng đó. Khi số lần giữ lại của một đối tượng bằng 0, bộ nhớ của đối tượng đó sẽ được giải phóng và đối tượng đó không còn hợp lệ. Khi các đối tượng được giải phóng, phương thức transactionloc() của chúng được gọi để giải phóng quyền sở hữu các biến thực thể của chúng.

Một vấn đề với kỹ thuật này là cách chuyển quyền sở hữu một đối tượng. Ví dụ: phương thức ban đầu có thể được gọi để tạo một đối tượng. Nếu phương thức nhà máy giải phóng đối tượng trước khi trả về (vì phương thức này không còn muốn sở hữu đối tượng nữa), thì đối tượng đó sẽ được giải phóng trước khi phương thức gọi có thể giữ lại đối tượng đó.

Để chuyển quyền sở hữu của một đối tượng, một phương thức sẽ gửi đối tượng đó một thông báo phát hành tự động (thay vì thông báo phát hành), thao tác này trì hoãn thông báo phát hành. Điều này cho phép phương thức nhà máy tạo một đối tượng sẽ được trả về và từ bỏ quyền sở hữu của đối tượng đó mà không làm mất hiệu lực đối tượng. Tại các khoảng thời gian đều đặn (chẳng hạn như sau mỗi lần lặp lại vòng lặp sự kiện trong một ứng dụng iOS), nhóm tự động phát hành sẽ bị "rút nước", nghĩa là tất cả đối tượng trong nhóm đó đều được gửi các thông báo phát hành bị trì hoãn. Mọi đối tượng có số lần giữ lại giảm về 0 đều được giải phóng như bình thường.

Vì gánh nặng về việc quản lý bộ nhớ thuộc về nhà phát triển, nên rất dễ bị rò rỉ bộ nhớ bằng phương pháp đếm tham chiếu. Tuy nhiên, Apple đề xuất một số phương pháp hay nhất để giảm thiểu vấn đề do J2ObjC triển khai.

Ngoài ra, chúng tôi còn hỗ trợ thời gian chạy và công cụ để phát hiện rò rỉ bộ nhớ. Môi trường thời gian chạy Objective-C báo cáo mọi sự cố rò rỉ được phát hiện khi một ứng dụng thoát. Đây là một lý do khiến J2ObjC chuyển các kiểm thử JUnit thành các tệp nhị phân có thể thực thi. Xcode sử dụng Clang và trình biên dịch đó có tính năng phân tích tĩnh tuyệt vời cho các vấn đề về bộ nhớ mà Xcode cung cấp cùng với lệnh Phân tích.

Đếm tham chiếu tự động (ARC)

ARC là phương thức quản lý bộ nhớ mà Apple đề xuất. Hàm này di chuyển trách nhiệm đếm tham chiếu đến trình biên dịch, đồng thời thêm các phương thức giữ lại, phát hành và tự động phát hành thích hợp trong quá trình biên dịch. ARC hỗ trợ các tham chiếu yếu cho các thiết bị chạy iOS 5 trở lên.

Các dự án nên sử dụng ARC cho bản dịch mã. Mã Objective-C được dịch mã cũng giống như mã Objective-C được viết thủ công. Việc sử dụng ARC có thể giúp các nhà phát triển tránh các lỗi phổ biến liên quan đến bộ nhớ, chẳng hạn như giải phóng quá mức hoặc tham chiếu thiếu, giúp việc quản lý bộ nhớ trở nên đơn giản hơn và ít xảy ra lỗi hơn.

Xin lưu ý rằng theo mặc định, ARC không an toàn cho trường hợp ngoại lệ. Cụ thể, lỗi này sẽ làm rò rỉ bộ nhớ khi gửi các ngoại lệ. Vì các ngoại lệ phổ biến hơn trong Java và thường có thể khôi phục được, nên điều này có thể gây ra vấn đề. Việc sử dụng -fobjc-arc-exceptions khi biên dịch bằng vòng cung sẽ khắc phục các sự cố rò rỉ với chi phí hiệu suất có thể chấp nhận được.

Các dự án mới cũng nên sử dụng ARC cho mã Objective-C được viết thủ công và chỉ quay lại sử dụng cách đếm tham chiếu thủ công nếu dữ liệu phân tích cho thấy vấn đề về hiệu suất thực tế. Cả mã ARC và không phải ARC đều có thể được biên dịch và liên kết vào cùng một ứng dụng mà không gặp vấn đề gì.

Tệp đối chiếu yếu

Bạn có thể chú thích các trường bằng com.google.devtools.j2objc.Weak. Trình chuyển đổi sẽ sử dụng thành phần này để tạo các trường tuân theo ngữ nghĩa tham chiếu yếu Objective-C. Khi sử dụng phương pháp đếm tham chiếu, điều này có nghĩa là trường này không được lưu giữ khi khởi chạy và được giải phóng tự động khi thực thể chứa được giải phóng. Trong ARC, các trường yếu được đánh dấu bằng chú giải __unsafe_unretained và các thuộc tính liên quan được khai báo là yếu.

Trong một số trường hợp, thực thể của lớp bên trong sẽ tham gia chu kỳ tham chiếu với thực thể bên ngoài. Ở đây, chú giải com.google.devtools.j2objc.WeakOuter sẽ được dùng để đánh dấu lớp bên trong, do đó, thông tin tham chiếu đến lớp bên ngoài sẽ được xử lý như mô tả ở trên. Các trường khác trong lớp bên trong không bị chú thích này ảnh hưởng.

J2ObjC cũng hỗ trợ lớp WeakReference, vì vậy mã Java sử dụng lớp này sẽ hoạt động tương tự khi được dịch. Xin lưu ý rằng WeakReference vốn không xác định trên JVM; các ứng dụng muốn tránh rò rỉ bộ nhớ mà vẫn duy trì khả năng dự đoán nên ưu tiên @Weak@WeakOuter.

Công cụ quản lý bộ nhớ

  • Công cụ tìm chu kỳ – phân tích các tệp nguồn Java để có các chu kỳ tham chiếu đối tượng mạnh.
  • Công cụ mã XML – Bộ công cụ phân tích tài nguyên của Xbox.
  • Xcode Memory Diagnostics (Chẩn đoán bộ nhớ Xcode) – các lựa chọn xây dựng để chạy cùng với tính năng ghi nhật ký và chẩn đoán bộ nhớ.