Những loại rò rỉ nào khi tham chiếu tự động đếm trong Objective-C không ngăn chặn hoặc giảm thiểu?


235

Trong nền tảng Mac và iOS, rò rỉ bộ nhớ thường được gây ra bởi các con trỏ chưa được phát hành. Theo truyền thống, việc kiểm tra allocs, bản sao và giữ lại của bạn luôn luôn là cực kỳ quan trọng để đảm bảo mỗi bản có một thông báo phát hành tương ứng.

Chuỗi công cụ đi kèm với Xcode 4.2 giới thiệu tính năng tham chiếu tự động (ARC) với phiên bản mới nhất của trình biên dịch LLVM , điều đó hoàn toàn giải quyết vấn đề này bằng cách đưa trình biên dịch vào bộ nhớ quản lý công cụ của bạn cho bạn. Điều đó khá tuyệt, và nó đã cắt giảm rất nhiều thời gian phát triển trần tục, không cần thiết và ngăn chặn rất nhiều rò rỉ bộ nhớ bất cẩn, dễ khắc phục với sự cân bằng giữ / giải phóng hợp lý. Ngay cả các nhóm tự động phát hành cũng cần được quản lý khác nhau khi bạn bật ARC cho ứng dụng Mac và iOS của mình (vì bạn không nên phân bổ NSAutoreleasePools của riêng mình nữa).

Nhưng những gì rò rỉ bộ nhớ khác không ngăn cản mà tôi vẫn phải coi chừng?

Là một phần thưởng, sự khác biệt giữa ARC trên Mac OS X và iOS và bộ sưu tập rác trên Mac OS X là gì?

Câu trả lời:


262

Vấn đề chính liên quan đến bộ nhớ mà bạn vẫn cần phải biết là giữ lại các chu kỳ. Điều này xảy ra khi một đối tượng có một con trỏ mạnh đến một đối tượng khác, nhưng đối tượng đích có một con trỏ mạnh trở lại ban đầu. Ngay cả khi tất cả các tham chiếu khác đến các đối tượng này bị xóa, chúng vẫn sẽ giữ cho nhau và sẽ không được phát hành. Điều này cũng có thể xảy ra một cách gián tiếp, bởi một chuỗi các đối tượng có thể có đối tượng cuối cùng trong chuỗi liên quan đến một đối tượng trước đó.

Vì lý do này mà các vòng loại __unsafe_unretained__weakquyền sở hữu tồn tại. Cái trước sẽ không giữ lại bất kỳ đối tượng nào mà nó trỏ tới, nhưng để ngỏ khả năng vật thể đó sẽ biến mất và nó chỉ vào bộ nhớ xấu, trong khi cái sau không giữ lại đối tượng và tự động đặt nó thành con số không khi mục tiêu của nó bị phá hủy. Trong số hai, __weakthường được ưa thích trên các nền tảng hỗ trợ nó.

Bạn sẽ sử dụng các vòng loại này cho những thứ như đại biểu, nơi bạn không muốn đối tượng giữ lại đại biểu của mình và có khả năng dẫn đến một chu kỳ.

Một vài mối quan tâm liên quan đến bộ nhớ quan trọng khác là việc xử lý các đối tượng và bộ nhớ Core Foundation được phân bổ sử dụng malloc()cho các loại như char*. ARC không quản lý các loại này, chỉ các đối tượng Objective-C, do đó bạn sẽ vẫn cần phải tự xử lý chúng. Các loại Core Foundation có thể đặc biệt khó khăn, bởi vì đôi khi chúng cần được bắc cầu để khớp với các đối tượng Objective-C và ngược lại. Điều này có nghĩa là điều khiển cần phải được chuyển qua lại từ ARC khi kết nối giữa các loại CF và Objective-C. Một số từ khóa liên quan đến việc bắc cầu này đã được thêm vào và Mike Ash có một mô tả tuyệt vời về các trường hợp bắc cầu khác nhau trong bài viết ARC dài của mình .

Ngoài ra, có một số trường hợp khác ít gặp hơn, nhưng vẫn có khả năng có vấn đề, mà đặc điểm kỹ thuật được công bố đi vào chi tiết.

Phần lớn hành vi mới, dựa trên việc giữ các đối tượng xung quanh miễn là có một con trỏ mạnh với chúng, rất giống với bộ sưu tập rác trên máy Mac. Tuy nhiên, nền tảng kỹ thuật rất khác nhau. Thay vì có một quy trình thu gom rác chạy đều đặn để dọn dẹp các đối tượng không còn bị chỉ ra, phong cách quản lý bộ nhớ này dựa trên các quy tắc lưu giữ / giải phóng cứng nhắc mà tất cả chúng ta cần phải tuân thủ trong Objective-C.

ARC chỉ đơn giản thực hiện các tác vụ quản lý bộ nhớ lặp đi lặp lại mà chúng ta phải thực hiện trong nhiều năm và chuyển chúng sang trình biên dịch để chúng ta không bao giờ phải lo lắng về chúng nữa. Bằng cách này, bạn không gặp phải sự cố tạm dừng hoặc cấu hình bộ nhớ răng cưa gặp phải trên nền tảng thu gom rác. Tôi đã trải nghiệm cả hai thứ này trong các ứng dụng Mac đã thu thập rác của mình và rất háo hức muốn xem cách chúng hoạt động theo ARC.

Để biết thêm về bộ sưu tập rác so với ARC, hãy xem phản hồi rất thú vị này của Chris Lattner trên danh sách gửi thư Objective-C , nơi anh liệt kê nhiều lợi thế của ARC so với bộ sưu tập rác Objective-C 2.0. Tôi đã gặp một số vấn đề về GC mà anh ấy mô tả.


2
Cảm ơn câu trả lời chi tiết. Tôi gặp vấn đề tương tự khi tôi xác định một đại biểu theo _unafe_unretained và ứng dụng của tôi bị lỗi, sau đó đã sửa nó bằng cách thay đổi thành mạnh nhưng bây giờ nó bị rò rỉ bộ nhớ. Vì vậy, tôi đã thay đổi nó thành yếu đuối và hoạt động như một lá bùa.
chathuram

@ichathura Wow! Bạn đã cứu tôi khỏi mire ARC. Tôi đã gặp sự cố tương tự khi sử dụng CMPopTipView.
Nianliang

@BradLarson: "bạn không gặp phải vấn đề tạm dừng hoặc hồ sơ bộ nhớ răng cưa gặp phải trên nền tảng thu gom rác". Tôi mong đợi các cấu hình bộ nhớ tạm dừng và răng cưa tồi tệ hơn từ khai hoang dựa trên phạm vi và hiệu suất kém hơn nhiều từ việc đếm tham chiếu vì vậy tôi muốn xem một so sánh thực sự.
Jon Harrop

Brad, liên kết từ Chris Lattner đã chết . Tôi không 100% nhưng tôi tìm thấy liên kết khác này. Mà tôi nghĩ là những gì bạn muốn liên kết đến: List.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/ chủ đề
Mật ong

1
@Honey - Cảm ơn bạn đã chỉ ra điều đó. Liên kết bạn liên kết hơi khác, nhưng tôi đã thay thế liên kết chết bằng phiên bản lưu trữ của tin nhắn gốc. Đó là trong kho lưu trữ danh sách gửi thư, sẽ có sẵn ở đâu đó, nhưng tôi sẽ xem liệu tôi có thể tìm thấy vị trí mới của họ không.
Brad Larson

14

ARC sẽ không giúp bạn với bộ nhớ không phải ObjC, ví dụ nếu bạn có malloc()thứ gì đó, bạn vẫn cần free()nó.

ARC có thể bị đánh lừa bởi performSelector:nếu trình biên dịch không thể tìm ra bộ chọn là gì (trình biên dịch sẽ tạo ra một cảnh báo về điều đó).

ARC cũng sẽ tạo mã theo các quy ước đặt tên ObjC, vì vậy nếu bạn trộn mã ARC và MRC, bạn có thể nhận được kết quả đáng ngạc nhiên nếu mã MRC không thực hiện được những gì trình biên dịch nghĩ.


7

Tôi gặp phải sự cố rò rỉ bộ nhớ trong ứng dụng của mình do 4 vấn đề sau:

  1. Không làm mất hiệu lực NSTimers khi loại bỏ bộ điều khiển xem
  2. Quên để xóa bất kỳ người quan sát nào đối với NSNotificationCenter khi bỏ qua bộ điều khiển xem.
  3. Giữ tài liệu tham khảo mạnh mẽ để tự trong khối.
  4. Sử dụng tham chiếu mạnh đến các đại biểu trong thuộc tính của bộ điều khiển xem

May mắn thay, tôi đã xem qua bài đăng trên blog sau đây và có thể sửa chúng: http://www.reigndesign.com/blog/debugging-retain- Motorcycle-in-objective-c-far-labilities -culprits /


0

ARC cũng sẽ không quản lý các loại CoreFoundation. Bạn có thể 'cầu nối' chúng (Sử dụng CFBridgingRelease()) nhưng chỉ khi bạn sẽ sử dụng nó làm đối tượng Objective-C / Ca cao. Lưu ý rằng CFBridgingRelease chỉ giảm số lần giữ lại CoreFoundation bằng 1 và chuyển nó sang ARC của Objective-C.


0

Xcode 9 cung cấp một công cụ tuyệt vời để tìm ra loại vấn đề đó. Nó được gọi là: " Đồ thị bộ nhớ gỡ lỗi ". Sử dụng nó, bạn có thể tìm thấy đối tượng bị rò rỉ của mình theo loại lớp và bạn có thể thấy rõ ai là người có tham chiếu mạnh đến nó, bằng cách giải phóng nó từ đó giải quyết vấn đề của bạn. Nó cũng phát hiện các chu kỳ bộ nhớ.

Xem thêm thông tin về cách sử dụng nó

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.