Phần 5: “Vật lộn” với việc quản lý bộ nhớ trong Objective-C


Phần 1: “Lần đầu” với lập trình Objective-C
Phần 2: “Khám phá” OOP trong Objective-C
Phần 3: “Quan hệ” giữa các đối tượng trong Objective-C
Phần 4: “Tự sướng A2Z” với một chương trình Objective-C hoàn thiện
Phần 5: “Vật lộn” với quản lý bộ nhớ trong Objective-C
Phần 6: Chuẩn bị “lên đỉnh” với iPhone application

Chào mừng bạn đến với bài 5 của loạt bài về Objective-C này. Trong bài này, chúng ta sẽ tìm hiểu việc quản lý bộ nhớ, một một phần rất quan trọng của Objective-C (và nhiều ngôn ngữ khác). Hầu hết các ngôn ngữ kịch bản (chẳng hạn như PHP) quản lý bộ nhớ một cách tự động, nhưng Objective-C đòi hỏi rằng chúng ta là cẩn thận với việc sử dụng bộ nhớ của chúng ta. Điều đó có nghĩa là ta phải biết cách tự tạo và giải phóng không gian cho các đối tượng mà chúng ta đang sử dụng.

Phương pháp

Trong Objective-C, có 2 phương pháp để quản lý bộ nhớ, thứ nhất là dùng reference và thứ hai là dùng garbage collection. Bạn cứ nghĩ đơn giản là 2 cách thức theo kiểu là tự làm hoặc tự động theo môi trường của Objective-C, cụ thể reference counting là chúng ta phải tự làm còn garbage collection là cơ chế tự động và tự động quản lý bộ nhớ trong chương trình của chúng ta. Một lưu ý quan trọng là garbage collection không hoạt động trên iPhone, đó là lý do tại sao chúng tôi sẽ không tập trung nhiều vào phương pháp này. Nếu bạn muốn phát triển chương trình dành cho MacOS, bạn có thể tham khảo thêm các tài liệu trên website dành cho Apple Developer.

Cú pháp (Syntax)

Có nhiều cách thức khác nhau để tạo ảnh hưởng tới việc quản lý bộ nhớ. Trước hết, khi bạn tạo một đối tượng bằng cách sử dụng phương thức “alloc” (tạo mới hoặc copy) thì thực chất là bạn đã cấp cho nó một ô nhớ có thể chứa một sự thể hiện cho đối tượng đó và bạn sẽ là người quản lý đối tượng đó. Điều này cũng đúng trong trường hợp bạn dùng phương thức “retain”. Sau khi bạn tạo đối tượng xong rồi nếu bạn gọi phương thức release, hoặc autorelease (sẽ nói thêm về điều này sau) của đối tượng đó, bạn không còn có quyền quản lý đối tượng hoặc đảm nhiệm những công việc liên quan đến đối tượng đó nữa hay đơn giản là toàn bộ ô nhớ dành cho đối tượng đã khởi tạo sẽ bị giải phóng. Đoạn mã lệnh sau sẽ minh họa quá trình alloc một đối tượng:

Car *myCar = [Car alloc];

Sau khi chạy câu lệnh này thì chúng ta sẽ chịu trách nhiệm quản lý đối tượng myCar và tự xây dựng quá trình release (hoặc autorelease) đối tượng trong giai đoạn sau khi không cần sử dụng nó nữa. Điều quan trọng cần lưu ý rằng nếu bạn cố tình tiến hành thao tác release một đối tượng đã được thiết lập để autorelease thì ứng dụng ứng dụng của bạn sẽ lỗi.

Khi chúng ta tạo ra một đối tượng bằng cách sử dụng phương thức alloc, đối tượng xe của chúng ta sẽ có giá trị đếm là 1, có nghĩa là nó sẽ không được deallocate. Câu lệnh sẽ như sau:

[myCar retain];

Sau đó, khi có đối tượng mới được tạo, giá trị đếm của chúng ta sẽ tăng lên là 2 còn khi một trong những đối tượng được tạo không còn tồn tại nữa thì giá trị đếm lại giảm đi 1. Chỉ cho đến khi giá trị đếm đó về thành 0 thì đối tượng car mới được deallocate.

Khối lệnh autorelease

Khi bạn đã tạo ra một project mới trong Xcode, bạn có thể nhận thấy một số đoạn mã lệnh xuất hiện theo mặc định ví dụ như khối autorelease. Từ những bài trước chúng ta đã gặp nhưng tạm thời bỏ qua và bây giờ là thời điểm ta sẽ tìm hiểu cụ thể xem khối lệnh đó làm gì? Dưới đây là khối lệnh mặc định được thêm vào file main.m:

autorelease

hoặc bạn có thể chủ động xây dựng kịch bản cho autorealease như sau:

  • NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [pool drain];
  • Trong đoạn mã trên ta sẽ thấy khi cần tạo ra khối lệnh xử lý autorelease thì ở trong câu lệnh thứ nhất chúng ta sẽ tạo một đối tượng từ lớp NSAutoReleasePool tên là pool và và câu lệnh thứ 2 sẽ kết thúc khối lệnh xử lý autorealse với lời gọi phương thức drain của đối tượng pool. Các câu lệnh mà khai báo trong phạm vi của 2 câu lệnh trên sẽ chịu ảnh hưởng của quá trình autorelease và cụ thể là chúng ta sẽ thấy nếu như các đối tượng được khởi tạo trong phạm vi này nếu như mà không còn có tham chiếu đến nó nữa thì nó sẽ tự động được release ra khỏi bộ nhớ mà chúng ta không cần phải tự viết thao tác release cho từng đối tượng.

    Giá trị retainCount

    Trước khi chúng tôi kết thúc, chúng ta hãy nhìn vào một cái gì đó mà có thể giúp làm cho bộ nhớ một chương quản lý dễ dàng hơn. Cho đến bài này chúng tôi đã tạo ra đối tượng và chúng tôi cũng biết có bao nhiêu bản thể hiện của đối tượng một đối tượng, nhưng làm thế nào để chỉ ra con số cụ thể đó? Đơn giản thôi, trên đối tượng thể hiện của chúng ta có một thuộc tính là retainCount và việc còn lại là ta chỉ cần in giá trị đó ra.

    NSLog (@"retainCount for car object:% d", [myCar retainCount]);

    retainCount trả về một số nguyên, vì vậy chúng tôi sử dụng %d để hiển thị giá trị trong phần định dạng.

    Tổng kết

    Thực sự việc quản lý bộ nhớ đối với hầu hết các ngôn ngữ đều là những vấn đề khá hóc búa. Một bài học chưa thể hướng dẫn chi tiết mọi vấn đề liên quan đến quản lý bộ nhớ. Vì vậy, chúng tôi có lời khuyên với những bạn mới học nên tạm cứ sử dụng những cơ chế tự động có sẵn trong Objective-C và khi đã có kinh nghiệm thì chúng ta sẽ đọc thêm tài liệu để tìm hiểu kỹ hơn về vấn đề này.

    Đến đây là kết thúc bài học thứ 5 và để có thể tìm hiểu thêm một số chức năng mở rộng của những lớp thuộc framework Cocoa Touch (giúp cho các bạn muốn phát triển ứng dụng trên iPhone sau này) xin mời các bạn đọc bài học cuối cùng trong seri này

    Leave a Reply

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out /  Change )

    Google photo

    You are commenting using your Google account. Log Out /  Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out /  Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out /  Change )

    Connecting to %s

    %d bloggers like this: