内存机制#
make_object
#
template <typename T, typename... Args>
inline ObjectPtr<T> make_object(Args&&... args);
make_object
,它的作用是使用默认的分配器来分配一个对象。
参数列表中包括了三个参数:
T
:节点类型,是一个模板参数;Args
:构造函数的参数,也是一个模板参数;args
:可变参数,表示传递给构造函数的参数。
函数返回值类型为ObjectPtr<T>
,即指向类型为 T
的对象的指针。
在函数体内部,使用了模板展开的方式传递参数给构造函数,最终调用了 TVM 中的默认分配器来分配新的对象,并返回该对象的指针。
template <typename T, typename... Args>
inline ObjectPtr<T> make_object(Args&&... args) {
return SimpleObjAllocator().make_object<T>(std::forward<Args>(args)...);
}
make_object
函数使用了名为 SimpleObjAllocator
的对象来进行对象的分配和释放操作。在函数内部,首先调用了 SimpleObjAllocator
的默认构造函数来创建 SimpleObjAllocator
对象。然后,通过调用 make_object<T>(std::forward<Args>(args)...)
来创建类型为 T
的对象,并将传入的参数进行完美转发(std::forward<Args>(args)...
)传递给对象的构造函数。最后,将创建的对象指针作为函数的返回值返回。
这个函数的作用是简化对象的创建过程,通过传入类型和参数,可以快速创建指定类型的对象,并返回其指针。
make_inplace_array_object
#
模板函数 make_inplace_array_object
,它接受可变参数 size_t num_elems, Args&&... args
,并返回 ObjectPtr<ArrayType>
类型的对象指针。
该函数使用了名为 SimpleObjAllocator
的对象来进行对象的分配和释放操作。在函数内部,首先调用了 SimpleObjAllocator
的默认构造函数来创建 SimpleObjAllocator
对象。然后,通过调用 make_inplace_array<ArrayType, ElemType>(num_elems, std::forward<Args>(args)...)
来创建指定元素个数的数组对象,并将传入的元素个数和参数进行完美转发(std::forward<Args>(args)...
)传递给数组对象的构造函数。最后,将创建的数组对象指针作为函数的返回值返回。
这个函数的作用是简化数组对象的创建过程,通过传入元素个数和参数,可以快速创建一个指定元素个数的数组对象,并返回其指针。
内存分配器的设计说明
允许在必要时交换分配器模式,这意味着 TVM 的内存分配器可以根据不同的需求和场景进行灵活的切换。
一些可能的未来优化方向:
使用 Arena 分配器,将内存所有权交给 Arena(deleter_= nullptr),这种分配器可以更好地管理内存块的大小和生命周期;
线程本地对象池:为每个大小和对齐要求创建一个对象池,这种优化可以提高多线程程序的性能;
通过对象的类型进行特化,为每个对象提供特定的分配器,这种优化可以更好地满足不同类型对象的内存需求。
ObjAllocatorBase
#
ObjAllocatorBase
模板类,它是所有对象分配器的基类。该类使用了 Curiously recurring template pattern,即在派生类中实现与基类相同的模板函数。
该类中有两个模板函数:
make_object(Args&&... args)
:用于创建新的对象,其中T
是要分配的类型,Args
是构造函数的参数类型,args
是实际传入的参数。该函数首先获取派生类中的Handler
模板类,然后使用Handler::New()
方法创建新的对象,并设置对象的type_index_
和deleter_
,最后返回指向该对象的指针。make_inplace_array(size_t num_elems, Args&&... args)
:用于创建指定元素个数的数组,其中ArrayType
是数组类型,ElemType
是数组元素的类型,num_elems
是数组元素的数量,args
是实际传入的参数。该函数首先获取派生类中的ArrayHandler
模板类,然后使用Handler::New()
方法创建新的对象数组,并设置数组的type_index_
和deleter_
,最后返回指向该对象数组的指针。
这两个函数都使用了静态断言(static_assert)来确保创建的对象类型为 Object
或其派生类。
SimpleObjAllocator
#
SimpleObjAllocator
,它继承自 ObjAllocatorBase<SimpleObjAllocator>
(这是 C++ 的 CRTP 实现静态多态技巧)。该分配器使用 new/delete
来管理对象的内存分配和释放。
该分配器中定义了两个嵌套模板类:Handler
和 ArrayHandler
。Handler
用于创建单个对象,而 ArrayHandler
用于创建对象数组。这两个类都使用了静态断言(static_assert)来确保对象类型符合特定的要求。
在 Handler
类中,使用 new
运算符创建新的对象,并使用 std::aligned_storage
来分配具有特定对齐要求的存储空间。然后,使用 placement new
将新对象放置在已分配的存储空间中,并调用构造函数初始化对象。最后,返回指向新对象的指针。
在 ArrayHandler
类中,使用 new
运算符创建指定元素个数的新对象数组,并使用 std::aligned_storage
来分配具有特定对齐要求的存储空间。然后,使用 placement new
将新对象放置在已分配的存储空间中,并调用构造函数初始化数组。最后,返回指向新对象数组的指针。
在 Deleter
函数中,使用 delete
运算符释放对象或对象数组的内存。对于对象数组,需要使用 delete[]
运算符释放整个数组的内存。
总之,这段代码实现了简单的对象分配器,可以用于在程序中动态分配和释放对象或对象数组的内存。