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ư alloc, new, copy 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