Quản lý bộ nhớ obj-C
Quản lý bộ nhớ là một trong những quá trình quan trọng nhất trong bất kỳ ngôn ngữ lập trình nào. Đó là quá trình mà bộ nhớ của các đối tượng được cấp phát khi chúng được yêu cầu và phân bổ khi chúng không còn được yêu cầu nữa.
Quản lý bộ nhớ đối tượng là một vấn đề về hiệu suất; nếu một ứng dụng không giải phóng các đối tượng không cần thiết, bộ nhớ của nó sẽ tăng lên và hiệu suất bị ảnh hưởng.
Objective-C Các kỹ thuật quản lý bộ nhớ có thể được phân thành hai loại.
- "Phát hành giữ lại thủ công" hoặc MRR
- "Đếm tham chiếu tự động" hoặc ARC
"Phát hành giữ lại thủ công" hoặc MRR
Trong MRR, chúng tôi quản lý bộ nhớ một cách rõ ràng bằng cách tự theo dõi các đối tượng. Điều này được thực hiện bằng cách sử dụng một mô hình, được gọi là đếm tham chiếu, mà NSObject lớp Foundation cung cấp cùng với môi trường thời gian chạy.
Sự khác biệt duy nhất giữa MRR và ARC là việc giữ lại và phát hành được chúng tôi xử lý thủ công trước đây trong khi phần sau được tự động xử lý.
Hình sau đại diện cho một ví dụ về cách quản lý bộ nhớ hoạt động trong Objective-C.
Vòng đời bộ nhớ của đối tượng Class A được thể hiện trong hình trên. Như bạn có thể thấy, số lưu giữ được hiển thị bên dưới đối tượng, khi số lưu giữ của một đối tượng trở thành 0, đối tượng được giải phóng hoàn toàn và bộ nhớ của nó được phân bổ cho các đối tượng khác sử dụng.
Đối tượng Lớp A được tạo lần đầu tiên bằng cách sử dụng phương thức phân bổ / init có sẵn trong NSObject. Bây giờ, số lượng giữ lại trở thành 1.
Bây giờ, lớp B giữ lại Đối tượng của Lớp A và số lượng giữ lại của đối tượng Lớp A trở thành 2.
Sau đó, Lớp C tạo một bản sao của đối tượng. Bây giờ, nó được tạo như một thể hiện khác của Lớp A với cùng giá trị cho các biến thể hiện. Ở đây, số giữ lại là 1 và không phải là số giữ lại của đối tượng ban đầu. Điều này được thể hiện bằng đường chấm trong hình.
Đối tượng được sao chép được phát hành bởi Lớp C bằng cách sử dụng phương thức phát hành và số giữ lại trở thành 0 và do đó đối tượng bị phá hủy.
Trong trường hợp Đối tượng Lớp A ban đầu, số lượng giữ lại là 2 và nó phải được giải phóng hai lần để nó bị phá hủy. Điều này được thực hiện bằng các câu lệnh phát hành của Lớp A và Lớp B, làm giảm số lượng lưu giữ xuống 1 và 0, tương ứng. Cuối cùng, đối tượng bị tiêu diệt.
Quy tắc cơ bản của MRR
Chúng tôi sở hữu bất kỳ đối tượng nào chúng tôi tạo: Chúng tôi tạo một đối tượng bằng cách sử dụng phương thức có tên bắt đầu bằng "phân bổ", "mới", "sao chép" hoặc "mutableCopy"
Chúng ta có thể nắm quyền sở hữu một đối tượng bằng cách sử dụng giữ lại: Một đối tượng đã nhận thường được đảm bảo vẫn hợp lệ trong phương thức mà nó được nhận và phương thức đó cũng có thể trả lại đối tượng một cách an toàn cho người gọi của nó. Chúng tôi sử dụng giữ lại trong hai trường hợp -
Trong việc triển khai phương thức truy cập hoặc phương thức init, để có quyền sở hữu đối tượng mà chúng ta muốn lưu trữ dưới dạng giá trị thuộc tính.
Để ngăn một đối tượng bị mất hiệu lực như một tác dụng phụ của một số thao tác khác.
Khi chúng ta không còn cần đến nó nữa, chúng ta phải từ bỏ quyền sở hữu đối với một đối tượng mà chúng ta sở hữu: Chúng ta từ bỏ quyền sở hữu đối với một đối tượng bằng cách gửi cho nó một thông báo phát hành hoặc một thông báo tự động tái phát. Theo thuật ngữ Cocoa, việc từ bỏ quyền sở hữu một đối tượng do đó thường được gọi là "giải phóng" một đối tượng.
Bạn không được từ bỏ quyền sở hữu đối tượng mà bạn không sở hữu: Đây chỉ là hệ quả của các quy tắc chính sách trước đây được nêu rõ ràng.
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
[super dealloc];
}
@end
int main() {
/* my first program in Objective-C */
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
NSLog(@"Retain Count after initial allocation: %d",
[sampleClass retainCount]);
[sampleClass retain];
NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
[sampleClass release];
NSLog(@"SampleClass dealloc will be called before this");
// Should set the object to nil
sampleClass = nil;
return 0;
}
Khi chúng ta biên dịch chương trình trên, chúng ta sẽ nhận được kết quả sau.
2013-09-28 04:39:52.310 demo[8385] Hello, World!
2013-09-28 04:39:52.311 demo[8385] Retain Count after initial allocation: 1
2013-09-28 04:39:52.311 demo[8385] Retain Count after retain: 2
2013-09-28 04:39:52.311 demo[8385] Retain Count after release: 1
2013-09-28 04:39:52.311 demo[8385] Object deallocated
2013-09-28 04:39:52.311 demo[8385] SampleClass dealloc will be called before this
"Đếm tham chiếu tự động" hoặc ARC
Trong Đếm Tham chiếu Tự động hoặc ARC, hệ thống sử dụng cùng một hệ thống đếm tham chiếu như MRR, nhưng nó chèn các lệnh gọi phương thức quản lý bộ nhớ thích hợp cho chúng tôi tại thời điểm biên dịch. Chúng tôi rất khuyến khích sử dụng ARC cho các dự án mới. Nếu chúng tôi sử dụng ARC, thường không cần hiểu cách triển khai cơ bản được mô tả trong tài liệu này, mặc dù nó có thể hữu ích trong một số trường hợp. Để biết thêm về ARC, hãy xem Chuyển đổi sang Ghi chú phát hành ARC.
Như đã đề cập ở trên, trong ARC, chúng ta không cần thêm các phương thức phát hành và giữ lại vì điều đó sẽ do trình biên dịch xử lý. Trên thực tế, quy trình cơ bản của Objective-C vẫn giống nhau. Nó sử dụng các hoạt động lưu giữ và phát hành nội bộ, giúp nhà phát triển viết mã dễ dàng hơn mà không phải lo lắng về các hoạt động này, điều này sẽ làm giảm cả lượng mã được viết và khả năng rò rỉ bộ nhớ.
Có một nguyên tắc khác được gọi là thu gom rác, được sử dụng trong Mac OS-X cùng với MRR, nhưng kể từ khi nó không được sử dụng trong OS-X Mountain Lion, nó đã không được thảo luận cùng với MRR. Ngoài ra, các đối tượng iOS không bao giờ có tính năng thu gom rác. Và với ARC, OS-X cũng không sử dụng tính năng thu gom rác.
Đây là một ví dụ ARC đơn giản. Lưu ý rằng điều này sẽ không hoạt động trên trình biên dịch trực tuyến vì nó không hỗ trợ ARC.
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
- (void)sampleMethod;
@end
@implementation SampleClass
- (void)sampleMethod {
NSLog(@"Hello, World! \n");
}
- (void)dealloc {
NSLog(@"Object deallocated");
}
@end
int main() {
/* my first program in Objective-C */
@autoreleasepool {
SampleClass *sampleClass = [[SampleClass alloc]init];
[sampleClass sampleMethod];
sampleClass = nil;
}
return 0;
}
Khi chúng ta biên dịch chương trình trên, chúng ta sẽ nhận được kết quả sau.
2013-09-28 04:45:47.310 demo[8385] Hello, World!
2013-09-28 04:45:47.311 demo[8385] Object deallocated