Cocos2d-x的内存管理(2)
Vector
Vector 是 Cocos2d-x 3.x 系列之后引入的新数据结构,它综合了 std::vector 的诸多函数,能便捷地进行各类数据操作,同时融入了 Cocos2d-x 的内存管理机制。
与普通类型(如 sprite)不同,Vector 是用于存储一组数据的容器,从其名称便可推断,它需要管理一大块内存。例如,可将 5 个 sprite 对象存入一个 Vector 中,此时 Vector 不仅要对这 5 个 sprite 进行内存管理,还需具备高效地对这些数据进行插入、删除、搜索等操作的能力。
为实现对存储元素的内存管理,Vector 采用了 Cocos2d-X 的引用计数和智能指针理念。具体而言,Vector 本身是局部变量,其内存分配在栈上,不占用堆内存,因此它的生命周期受作用域控制。在 Vector 的析构函数中,会自动进行内存释放操作。此外,传入 Vector 的变量必须是 Ref 的子类,这样才能使用引用计数的 retain 和 release 函数。在对 Vector 进行操作时,会根据不同操作进行相应的内存管理:
- 在执行
copy、pushBack、insert、replace操作时,会对元素调用retain函数,增加元素的引用计数。 - 在执行
popback、erase、clear、replace操作时,会对元素调用release函数,减少元素的引用计数。 - 在执行
swap、move操作时,不会对元素进行内存管理。
为了方便有效地操作数据,Vector 基于 std::vector 进行了封装,它不仅提供了 std::vector 的常用方法,如 begin、end、capacity、size、empty、max_size、getIndex、front、back、shrinkToFit 等,还自定义了一些方法,如 replace、swap、find 等。
Map
Map 与 Vector 类似,它包装了 std::unordered_map 和 std::map,同样融入了 Cocos2d-x 的内存管理机制。
unordered_map 会将键(key)转换为哈希值(hash),并按照哈希值的顺序存储元素,而非按照键或值的顺序。在进行搜索操作时,会先将键转换为哈希值,然后进行查找,其算法复杂度最快为 O(1),最慢为 O(n)。unordered_map 的哈希算法基于一个固定值 buckets 进行计算,因此在创建 Map 时,需要设定一个 buckets 值,该值类似于 reserve 的 capacity。如果 Map 中存储的元素数量超过 buckets,就需要重新计算哈希值。所以,需要根据元素插入的频繁程度和数量来权衡,确定创建 Map 时 reserve 的 capacity。另外,如果键为 int 类型,会直接使用该键作为哈希值。
在内存管理方面,Map 的值(value)相当于 Vector 的元素。在内存管理过程中,Vector 会对元素进行 retain 和 release 操作,而 Map 则会对值(即 iter->second)进行同样的操作。
Value
Vector 和 Map 都属于容器类型,而 Value 则是一个包装体,它可以包装 Int、Float、Vector 等所有数据结构。所有数据都可以定义为 Value 类型,然后通过 Value 提供的方法进行数据类型转换,并通过 Value 的析构函数进行内存管理。
Value 的构造函数接受一个参数,该参数用于为 Value 赋值,并确定其数据类型。例如,如果传入的参数为 int 类型,那么 Value 就是 int 类型的数据;如果传入的参数为 std::vector,则会在堆上分配一块内存来存储该 vector,并进行赋值。
由于 Value 通常是局部对象,在其生命周期结束时,会调用析构函数,释放之前分配的内存(如 vector)。在进行赋值操作时,如果 Value 本身的数据类型与新参数的数据类型不匹配,例如之前存储的是 std::vector,新参数为 std::unordered_map,则会先释放之前分配的内存,再重新分配一块新的内存。如果是 move 操作,只需清空原有的数据,然后将参数的数据移动过来,并将参数的类型设置为 none。在进行数据类型转换时,如果可以转换则进行转换,否则将转换结果设为 0。