Thứ Hai, 1 tháng 7, 2013

LẬP TRÌNH OBJECTIVE-C - part 5

7.     Quản lý bộ nhớ, ARC (Automactic Reference Counting)

-          Quản lý bộ nhớ là quản lý việc khởi tạo vùng nhớ cho ứng dụng, sử dụng nó và giải phóng nó khi ta đã hoàn thành công việc. Một chương trình quản lý bộ nhớ tốt sẽ sử dụng ít vùng nhớ nhất có thể.
 -          Manual Reference Counting (MRC) : quản lý bộ nhớ thủ công, có nghĩa là chúng ta sẽ tự quản lý bộ nhớ bằng cách đánh dấu, theo vết vòng đời của object. Cụ thể là ta sẽ đếm việc khởi tạo, sử dụng và giải phóng object trong chương trình.
-          Autiomatic Reference Counting (ARC) : quản lý bộ nhớ tự động, hệ thống sẽ dùng bộ đếm tương tự như MRC nhưng nó sẽ thêm vào phương thức quản lý bộ nhớ tự động tại thời điểm compile.
-          Garbage Collection (GC) : hệ thống sẽ tự động lưu vết và tự động giải phóng vùng nhớ của object không cần thiết nữa. Nó sử dụng kỹ thuật quản lý bộ nhớ khác với MRC và ARC, tuy nhiên GC chỉ hỗ trợ Mac OS X mà không hỗ trợ iOS.

l  Reference Counting
-          Reference Counting(hoặc Retain Counting) : là một kỹ thuật quản lý bộ nhớ của Objective-C nhằm theo vết vòng đời của đối tượng(object), đếm số lượng tham chiếu đến một đối tượng.
-          Reference Count(hoặc Retain Count) : số lượng tham chiếu đến một đối tượng.
-          Khi đối tượng được khởi tạo bằng các từ khóa như allocnewcopy  thì reference count của nó sẽ tự động là 1.
-          Để tăng reference count lên 1, ta gửi thông điệp retain cho đối tượng.
-          Để giảm reference count xuống 1, ta gửi thông điệp release cho đối tượng.
-          Để có thể biết được reference count hiện tại, ta gửi thông điệp retainCount cho đối tượng.
-          Khi reference count giảm xuống 0 thì đối tượng sẽ được hủy, vùng nhớ được giải phóng, lúc này hệ thống sẽ tự động gửi thông điệp dealloc cho đối tượng. 

l  Ví dụ:
-          alloc hoặc new  
Mục đích : 
Cấp phát bộ nhớ cho đối tượng.
Reference count : bằng 1
Ví dụ:
NSString *str = [[NSString alloc] init];
NSString *str = [NSString new];

-          copy
Mục đích : 
Cấp phát bộ nhớ cho đối tượng thông qua một đối tượng khác.
Reference count : bằng 1
Ví dụ:
NSString *str = [someString copy];
NSString *str = [someString copy];

-          retain  
Mục đích : 
Gọi khi ta cần sử dụng một đối tượng, mà đối tượng đó đã được cấp phát ở đâu đó, ta không chắc là tại thời điểm ta sử dụng thì đối tượng đó có bị release hay không. Gọi retain giống như ta thông báo cho chủ sở hữu của nó là “Đừng xóa nó cho đến khi tôi sử dụng nó xong nhé !”. Khi gọi retain thì lúc này chúng ta là chủ sở hữu mới của nó(bên cạnh chủ sở hữu cũ). Khi nào sử dụng xong ta cần phải release nó.
Reference count : tăng thêm 1
Ví dụ:
NSString *str = [[NSString alloc] initWithString:@”Hello”];
NSString *str2 = str;
[str release];
//Sau vài giây thì str2 không còn lưu đúng nội dung

Trong ví dụ trên, biến str2 chỉ đơn giản là trỏ đến vùng nhớ của biến str, một khi ta giải phóng biến str thì biến str2 sẽ lưu không còn đúng nội dung nữa. Giải pháp :
NSString *str = [[NSString alloc] initWithString:@”Hello”];
NSString *str2 = [str retain];
[str release];
//str2 vẫn còn lưu đúng nội dung cho tới khi ta giải phóng nó
[str2 release];

-          release
Mục đích
Báo cho hệ thống biết là ta đã sử dụng xong 1 đối tượng nào đó và cần giải phóng nó. Đối tượng sẽ thực sự được giải phóng chỉ khi không còn ai sở hữu nó nữa (reference count = 0)
Reference count : Giảm xuống 1 ngay lập tức.

-          autorelease  
Mục đích
- Khi ta không muốn giải phóng một đối tượng nào đó ngay lập tức.
- Khi ta không muốn phải ghi nhớ lúc nào nên release những đối tượng mà ta đã cấp phát khi sử dụng xong.

- Khi ta muốn thêm một đối tượng vào autorelease pool.
Reference count : Giảm xuống 1 nhưng không ngay lập tức.

-          Convenience methods
Khái niệm :
Là những phương thức static, dùng để cấp phát và khởi tạo đối tượng một cách trực tiếp. Đối tượng được tạo ra từ phương thức convenience gọi là autorelease object, và ta không sở hữu đối tượng này.
NSString *str2 = [NSString stringWithFormat:@”%d”, 4]; 

- Tất cả các autorelease objects  được tạo ra sẽ được thêm vào autorelease pool  hiện tại.

-          Autorelease Pool  
Khái niệm : 
Là nơi chứa và giải phóng các autorelease objects . Khi autorelease pool  được giải phóng (thường là hết vòng lặp hay kết thúc hàm) thì các object nằm bên trong nó cũng sẽ được tự động giải phóng.

Khi nào nên sử dụng : 
- Khi ta muốn tự hủy một loạt các autorelease objects.
- Trong trường hợp cụ thể khi ta sử dụng nhiều biến tạm và muốn tránh phải cấp phát và release tất cả những biến này khi sử dụng xong.
- Hoặc ta không muốn đợi autorelease pool  của hệ thống được giải phóng, ta sẽ sử dụng đối tượng thuộc lớp NSAutoreleasePool

NSString *str2 = [NSString stringWithFormat:@”%d”, 4]; 
for (int i = 0; i <= 99999; i++)  {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *str1 = [NSString stringWithFormat:@”%d”, i];
NSString *str2 = [NSString stringWithFormat:@”%d”, i];
//...
}
[pool release];//Các autorelease objects ở trên sẽ đc giải phóng
}

Như ví dụ trên đây, nếu như ta không dùng lớp NSAutoreleasePool  thì khi chạy hết 99999 vòng lặp, cácautorelease objects  nằm trong autorelease pool  mới được giải phóng, và điều đó sẽ gây ra hiện tượng tràn bộ nhớ.

-          Hệ quả từ Autorelease Pool
Khi trong hàm ta sử dụng nhiều biến được cấp phát, và không muốn suy nghĩ lúc nào nên release biến này, lúc nào nên release biến kia, ta chỉ cần kẹp đoạn code giữa NSAutoreleasePool , rồi cho biến đó autorelease, sau đó ta vẫn sử dụng nó được bình thường.

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Animal *animal = [[Animal alloc] initWithName:@"Animal"];
[animal autorelease];
Zoo *zoo = [[Zoo alloc] init];
[zoo autorelease];
[zoo add:animal];
[pool release];
tài liệu tham khảo

Không có nhận xét nào:

Đăng nhận xét