Search…

Quản Lý Bộ Nhớ trong Cocos2d-x

30/09/20203 min read
Giới thiệu cấp phát và thu hồi bộ nhớ trong Cocos2d-x

Nếu là người mới bắt đầu làm quen với Cocos2d-x, chắc hẳn đa số đều cảm thấy bỡ ngỡ trước cách quản lý bộ nhớ của Cocos2d-x khi không thấy bất kỳ hàm new hay delete nào trong 1 game “thuần” Cocos2d-x.

Bài viết này sẽ giải đáp thắc mắc làm thế nào Cocos2d-x có thể cấp phát/thu hồi bộ nhớ của các đối tượng.

Reference Counting

Reference counting là 1 kỹ thuật để lưu trữ số lượng tham khảo, con trỏ đến 1 tài nguyên như các đối tượng, vùng nhớ hoặc các tài nguyên khác. 

Ví dụ:

int main()
{
	int *pi = new int;
	*pi = 10;
	int *pi_1 = pi;
	int *pi_2 = pi;

	return 0;
}

Trong ví dụ trên, tài nguyên là 1 vùng nhớ dùng để lưu trữ số nguyên kiểu int.

  • Sau khi chương trình chạy dòng thứ 3, có 1 con trỏ “nắm giữ” tài nguyên.
  • Sau khi chương trình chạy dòng thứ 5, 6 sẽ có lần lượt 2, 3 con trỏ “nắm giữ” tài nguyên. Reference counting là 1 kỹ thuật để lưu trữ những con số này.

Nhược điểm của cách quản lý bộ nhớ thông thường

Với cách quản lý bộ nhớ chỉ sử dụng 2 toán tử newdelete, rất khó để có thể biết được 1 tài nguyên còn được sử dụng hay không. Điều này sẽ gây khó khăn cho lập trình viên khi phải quyết định nên giải phóng hay giữ lại tài nguyên đã cấp phát. Ví dụ:

int main()
{
	int *pi = new int;
	*pi = 10;
	int *pi_1 = pi;
	int *pi_2 = pi;

	delete pi_1;

	*pi = 11;
	*pi_2 = 12;

	return 0;
}

Tại dòng 8, lập trình viên không muốn sử dụng pi_1 nữa nên đã giải phóng tài nguyên được quản lý bởi pi_1. Điều đó cực kỳ nguyên hiểm vì ngoài pi_1 ra vẫn còn pipi_2 “nắm giữ” và có nhu cầu sử dụng tài nguyên chung này. Việc sử dụng tài nguyên dùng chung không hợp lý có thể làm cho chương trình phải “dừng lại khi chưa được phép”.

CCAutoreleasePool

CCAutoreleasePool là 1 phương pháp để quản lý bộ nhớ trong Cocos2d-x dựa trên kỹ thuật Reference counting. Các tài nguyên trong pool có reference counting bằng 0 sẽ tự động được giải phóng lúc kết thúc mỗi lần lặp (message loop).

Retain

Khi  gọi ptr->retain() nghĩa là đã báo cho chương trình biết con trỏ ptr nắm giữ tài nguyên nó đang trỏ đến. Reference counting sẽ tăng lên 1 đơn vị.

Release

Khi gọi ptr->release() nghĩa là đã báo cho chương trình biết con trỏ ptr không còn nắm giữ tài nguyên nó đang trỏ đến nữa. Reference counting sẽ giảm xuống 1 đơn vị.

Autorelease

Khi gọi object->autorelease() đồng nghĩa với việc đưa đối tượng object vào CCAutoreleasePool. Tài nguyên được tham khảo bởi object sẽ được CCAutoreleasePool quản lý.

Ví dụ minh hoạ

bool StdioMemManLayer::init()
{
	_pSprite1 = CCSprite::create("texture_1.png");
	this->addChild(_pSprite1);

	_pSprite2 = CCSprite::create("texture_2.png");
}

void StdioMemManLayer::logRotation()
{
	CCLOG("_pSprite1 rotation: %.2f", _pSprite1->getRotation());
	CCLOG("_pSprite2 rotation: %.2f", _pSprite2->getRotation());
}

Các đối tượng CCSprite trong Cocos2d-x sẽ tự động gọi phương thức autorelease khi được tạo bởi phương thức create. Điều đó có nghĩa là đối tượng này được quản lý bởi CCAutoreleasePool.

_pSprite1 sau khi khởi tạo được thêm vào layer StdioMemManLayer sẽ được layer này nắm giữ tài nguyên, vì vậy lệnh gọi hàm tại dòng 11 sẽ không xảy ra sự cố gì cả.

Khác với _pSprite1, _pSprite2 sau khi khởi tạo đã không có “con trỏ” nào nắm giữ tài nguyên được trỏ tới bởi _pSprite2 nên lệnh gọi hàm tại dòng 12 sẽ gây crash chương trình vì CCAutoreleasePool đã giải phóng vùng nhớ _pSprite2 trỏ đến. Để đảm bảo câu lệnh này chạy đúng, lập trình viên phải gọi lệnh sau:

_pSprite2->retain();
IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024