虚拟内存管理
Runtime提供了一套虚拟内存管理的API接口,可供开发者更加精细化的管理其内存,例如:可以提前申请好大片的连续的虚拟内存,以简化后续的管理使用,同时可以按需在使用过程中申请物理内存并与虚拟内存做地址映射,即可以精细化管理,也可以最大化利用物理内存;此外还可以在进程之间利用虚拟内存管理中的handle来实现物理内存共享。
以下是一个虚拟内存的基本使用示例,申请好物理内存以及虚拟内存后,通过aclrtMapMem接口进行映射,即可通过虚拟地址访问对应的数据:
void SampleTest()
{
// 1. 查询内存申请粒度,并对size做对齐处理
// 设置要申请的物理内存属性
aclrtPhysicalMemProp prop = {};
prop.handleType = ACL_MEM_HANDLE_TYPE_NONE; // handle类型,当前仅支持 ACL_MEM_HANDLE_TYPE_NONE
prop.allocationType = ACL_MEM_ALLOCATION_TYPE_PINNED; // 内存分配类型,当前仅支持分配锁页内存
prop.memAttr = ACL_HBM_MEM_NORMAL; // 内存属性,这里申请HBM内存
prop.location.type = ACL_MEM_LOCATION_TYPE_DEVICE; // 内存所在位置,这里申请Device内存,且deviceId为0
prop.location.id = 0;
// 查询申请最小内存粒度
size_t granularity = 0UL;
aclrtMemGetAllocationGranularity(&prop, ACL_RT_MEM_ALLOC_GRANULARITY_MINIMUM, &granularity);
// 根据查询到的内存申请粒度做内存对齐,以便节约内存
const size_t dataSize = 1024 * sizeof(float);
size_t alignedSize = ((dataSize + granularity - 1U) / granularity) * granularity;
// 2. 申请物理内存
// 获取存放物理内存信息的handle,用于后续申请虚拟内存使用,需要注意的是handle并不能直接当虚拟地址访问
aclrtDrvMemHandle handle = nullptr;
aclrtMallocPhysical(&handle, alignedSize, &prop, 0); // 最后一个flag参数当前默认填0
// 3. 申请预留虚拟内存
void *virPtr;
// virPtr即为申请预留的虚拟地址指针,alignedSize为申请预留的内存大小
aclrtReserveMemAddress(&virPtr, alignedSize, 0, nullptr, 0);
// 4. 映射虚拟内存到物理内存上
// 将申请物理内存时获取的handle与申请预留的虚拟地址空间关联起来
// 需要注意的是,映射的内存大小alignedSize要与申请物理内存时设置的size大小一致
aclrtMapMem(virPtr, alignedSize, 0, handle, 0);
// 5. 设置虚拟内存访问权限
aclrtMemAccessDesc accessDesc = {};
accessDesc.flags = ACL_RT_MEM_ACCESS_FLAGS_READWRITE;
accessDesc.location.type = ACL_MEM_LOCATION_TYPE_DEVICE;
accessDesc.location.id = 0;
aclrtMemSetAccess(virPtr, alignedSize, &accessDesc, 1);
// 6. 内存访问
// 这里以Device->Host的内存拷贝为例,展示正常访问映射后的内存地址
int *hostPtr;
aclrtMallocHost(reinterpret_cast<void**>(&hostPtr), alignedSize);
aclrtMemcpy(hostPtr, alignedSize, virPtr, alignedSize, ACL_MEMCPY_DEVICE_TO_HOST);
aclrtFreeHost(hostPtr);
// 7. 取消虚拟内存与物理内存的映射
aclrtUnmapMem(virPtr);
// 8. 释放虚拟内存
aclrtReleaseMemAddress(virPtr);
// 9. 释放物理内存
aclrtFreePhysical(handle);
}
父主题: 内存管理