Unity il2cpp new 内存分配过程
Unity版本:Unity 2020.1.0f1
使用工具:Unity工程文件,IDA pro,X32dbg(这里都使用32位工程)
过程
源代码为
public class ClassNew{
public int a = 1;
public int b = 2;
public int c = 3;
}
classNew = new ClassNew();
il2cpp编译成的C++代码为
// classNew = new ClassNew();
ClassNew_t1698357DCBE408EC7AD7C866F038F723340D270E * L_16 = (ClassNew_t1698357DCBE408EC7AD7C866F038F723340D270E *)il2cpp_codegen_object_new(ClassNew_t1698357DCBE408EC7AD7C866F038F723340D270E_il2cpp_TypeInfo_var);
ClassNew__ctor_m6D3C0D4DD6A25602EBB11B3F5FC5268FD0CA2C40(L_16, /*hidden argument*/NULL);
这里就需要去寻找il2cpp_codegen_object_new这个函数
RuntimeObject* il2cpp_codegen_object_new(RuntimeClass *klass)
{
return il2cpp::vm::Object::New(klass);
}
Il2CppObject* Object::New(Il2CppClass *klass)
{
// same as NewAllocSpecific as we only support a single domain
return NewAllocSpecific(klass);
}
//再往下
Allocate(klass->instance_size, klass);
//之后可以看到
//如果分配内存小于等于7FFh就可以直接从ok_freelist直接分配这里更GC_generic_malloc_inner中的情况差不多(可以参考我另一篇贝姆垃圾回收的文章)
GC_malloc_kind_global(size_t lb, int k)
//如果没有符合的内存块还是会调用GC_generic_malloc_inner进行分配
GC_INNER void * GC_generic_malloc_inner(size_t lb, int k)
现在就来看看实例化classNew之后,贝姆回收器,会分配多少内存:
用x96dbg运行测试程序,断点打再new地方.
05955F30 | E8 9B320100 | call <gameassembly._GC_malloc_atomic>
//然后是GC_malloc_kind(lb, PTRFREE);
//发现lb是0x14有20个字节 GC_size_map[0x14] 为3,所以一共会分配24字节得块
//再去看ok_freelist是否有空闲得,可以看到一堆为24字节得块
0283C108 0283C0F0
0283C10C 00000000
0283C110 00000000
0283C114 00000000
0283C118 00000000
0283C11C 00000000
0283C120 0283C108
0283C124 00000000
0283C128 00000000
0283C12C 00000000
0283C130 00000000
0283C134 00000000
0283C138 05824DC8
0283C13C 00000000
0283C140 00000000
//最后等赋值完毕
0283C114 00000000
0283C118 00000000
0283C11C 00000000
0283C120 0E8D78F8
0283C124 00000000
0283C128 00000001
0283C12C 00000002
0283C130 00000003
0283C134 00000000
0283C138 05824DC8
0283C13C 00000000
0283C140 00000000
0283C144 00000000
0283C148 00000000
0283C14C 00000000
//证实了Unity BoemhGC 的分配方式
问题
问:ClassNew明明只占12个字节为啥,要0x14(20)个字节?
答:因为ClassNew在il2cpp中继承于Il2CppObject
typedef struct Il2CppObject
{
union
{
Il2CppClass *klass;//class类型数据
Il2CppVTable *vtable;//虚表数据
};
MonitorData *monitor;//监视数据
} Il2CppObject;
问:贝姆是如何决定分配内存时在freeptr还是在normal里的?
答:首先klass->has_references判断类中是否有引用
if (!klass->has_references)
{
o = NewPtrFree(klass);
}
#if IL2CPP_HAS_GC_DESCRIPTORS
else if (klass->gc_desc != GC_NO_DESCRIPTOR)
{
o = AllocateSpec(klass->instance_size, klass);
}
#endif
else
{
o = Allocate(klass->instance_size, klass);
}
其次看klass的来源,这里是由il2cpp_codegen_object_new(ClassNew_t1698357DCBE408EC7AD7C866F038F723340D270E_il2cpp_TypeInfo_var);传入ClassNew_t1698357DCBE408EC7AD7C866F038F723340D270E_il2cpp_TypeInfo_var这个值,被g_MetadataUsages列表所引用.列表会用global-metadata.dat初始化.
所以元数据global-metadata.dat的TypeInfo决定了,贝姆要分配什么样的内存,来龙去脉就是这样.
建议
1.创建class时,颗粒度要注意,32位和64位都会有8字节和16字节额外字节.
2.简单的数据结构就少加入引用,方便GC收集的删除.