已关闭
[Bug-Report|缺陷反馈]: 重复使用aclmdlLoadFromMemWithMem和aclmdlUnload加载卸载模型内存泄漏问题 #666
weixin_48253078创建于  5月27日关闭于  7月2日
weixin_48253078
weixin_48253078
5月27日 创建

在您提交issue前,请确认以下信息:

问题描述

在运行环境中,基于9.0.0nnrt包调用aclmdlLoadFromMemWithMem,aclmdlUnload接口重复加载卸载om模型,发现连续运行两天系统os内存保持缓慢增长,判断存在内存泄露

环境信息

300Vpro 310P3
CANN9.0.0 nnrt X86,ARM与开放态
固件 Ascend-hdk-310p-npu-firmware_9.0.0.0.205
驱动 Ascend-hdk-310p-npu-driver_26.0.rc1_linux

重现步骤

在运行环境中,基于9.0.0nnrt包调用aclmdlLoadFromMemWithMem,aclmdlUnload接口重复加载卸载om模型,发现连续运行两天系统os内存保持缓慢增长,判断存在内存泄露

预期结果

长时间连续运行aclmdlLoadFromMemWithMem,aclmdlUnload接口重复加载卸载om模型,系统os内存保持稳定,无内存泄漏

日志 / 截图

202605-181d882b1431ed094f274ac2c59fb29f.jpg

备注

likedislike
Sspring_yb
5月27日 将 wang-bin-789 设为负责人
wangbin
5月27日 评论:

感谢您的反馈:

使用aclmdlLoadFromMemWithMem 接口加载模型时,由于 workPtr 和 weightPtr 是由用户自行分配和管理的内存,麻烦确认一下,每次调用 aclmdlUnload 后,是否都同步释放了这些内存,以避免潜在的内存泄漏。

likedislike
weixin_48253078
weixin_48253078
5月27日 评论:

感谢您的反馈:

使用aclmdlLoadFromMemWithMem 接口加载模型时,由于 workPtr 和 weightPtr 是由用户自行分配和管理的内存,麻烦确认一下,每次调用 aclmdlUnload 后,是否都同步释放了这些内存,以避免潜在的内存泄漏。

@wang-bin-789

我这边check了我的测试代码并没有这个问题,以下是我的测试代码:

#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include "acl/acl.h"

// 错误检查宏
#define CHECK_ACL_RET(ret, err_code)
do {
if (ret != ACL_SUCCESS) {
printf("ACL error at %s:%d, error code: %d\n", FILE, LINE, ret);
return err_code;
}
} while(0)

// 读取文件到内存
int readFileToMemory(const char* filePath, void** buffer, size_t* fileSize) {
int fd = open(filePath, O_RDONLY);
if (fd < 0) {
printf("Failed to open file: %s\n", filePath);
return -1;
}

struct stat statbuf;
if (fstat(fd, &statbuf) < 0) {
    close(fd);
    return -1;
}

*fileSize = statbuf.st_size;
*buffer = malloc(*fileSize);
if (!*buffer) {
    close(fd);
    return -1;
}

ssize_t bytesRead = read(fd, *buffer, *fileSize);
close(fd);

if (bytesRead != (ssize_t)*fileSize) {
    free(*buffer);
    return -1;
}

return 0;

}

int main() {
aclError ret;
int device_id = 0;
uint32_t model_id = 0;

// 1. 初始化ACL
ret = aclInit(NULL);
CHECK_ACL_RET(ret, -1);

// 2. 设置设备
ret = aclrtSetDevice(device_id);
CHECK_ACL_RET(ret, -1);

// 3. 读取模型文件到内存
const char* model_path = "./models/om_dump_graph372.om";
void* model_buffer = NULL;
size_t model_size = 0;

if (readFileToMemory(model_path, &model_buffer, &model_size) != 0) {
    printf("Failed to read model file: %s\n", model_path);
    return -1;
}

printf("Model file loaded, size: %zu bytes\n", model_size);

// 4. 查询模型所需内存大小
size_t model_mem_size = 0;
size_t model_weight_size = 0;

ret = aclmdlQuerySize(model_path, &model_mem_size, &model_weight_size);
CHECK_ACL_RET(ret, -1);

printf("Model memory size: %zu, weight size: %zu\n", model_mem_size, model_weight_size);

// 5. 申请Device上模型执行的工作内存
void* model_mem_ptr = NULL;
ret = aclrtMalloc(&model_mem_ptr, model_mem_size, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_ACL_RET(ret, -1);

// 6. 申请Device上模型执行的权值内存
void* model_weight_ptr = NULL;
ret = aclrtMalloc(&model_weight_ptr, model_weight_size, ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_ACL_RET(ret, -1);

printf("Memory allocated successfully\n");

// 7. 测试aclmdlLoadFromMemWithMem接口
// 注意:这里使用从文件读取的内存数据,不是从文件直接加载
ret = aclmdlLoadFromMemWithMem(model_buffer, model_size, &model_id,
                               model_mem_ptr, model_mem_size,
                               model_weight_ptr, model_weight_size);
CHECK_ACL_RET(ret, -1);

printf("Model loaded successfully, model_id: %u\n", model_id);

// 8. 测试aclmdlUnload接口
ret = aclmdlUnload(model_id);
CHECK_ACL_RET(ret, -1);

printf("Model unloaded successfully\n");

// 9. 重复测试多次以检查内存泄漏
printf("Testing multiple load/unload cycles...\n");
for (int i = 0; i < 10000000; i++) {
    ret = aclmdlLoadFromMemWithMem(model_buffer, model_size, &model_id,
                                   model_mem_ptr, model_mem_size,
                                   model_weight_ptr, model_weight_size);
    CHECK_ACL_RET(ret, -1);
    
    ret = aclmdlUnload(model_id);
    CHECK_ACL_RET(ret, -1);
    
    if ((i + 1) % 20 == 0) {
        printf("Progress: %d/10000000\n", i + 1);
    }
}

printf("Test completed successfully! Total iterations: 100\n");

// 10. 清理资源
if (model_mem_ptr) {
    aclrtFree(model_mem_ptr);
    model_mem_ptr = NULL;
}

if (model_weight_ptr) {
    aclrtFree(model_weight_ptr);
    model_weight_ptr = NULL;
}

if (model_buffer) {
    free(model_buffer);
    model_buffer = NULL;
}

// 重置设备
ret = aclrtResetDevice(device_id);
CHECK_ACL_RET(ret, -1);

// 结束ACL
ret = aclFinalize();
CHECK_ACL_RET(ret, -1);

printf("Resources cleaned up successfully\n");

return 0;

}

likedislike
wangbin
5月30日 评论:

感谢您的反馈:
是否可提供om_dump_graph372.om模型使用了哪些类型的算子? 以便用于模拟复现和针对性的分析,谢谢

likedislike
weixin_48253078
weixin_48253078
6月3日 评论:

感谢您的反馈:
是否可提供om_dump_graph372.om模型使用了哪些类型的算子? 以便用于模拟复现和针对性的分析,谢谢

@wang-bin-789

所需om模型以及完整demo已通过邮件发送,麻烦尽快获取处理

likedislike
Wwangbin
6月10日 将 chenqian1365 设为负责人
wangbin
6月11日 评论:

感谢您的反馈:
om模型已经收到,进行了复现并抓取了相关的泄漏堆栈信息,初步分析在aclmdUnload执行时,可能存在泄漏的情况,详细信息进一步分析中。

likedislike
Cchenqian1365
6月11日 移除了负责人 chenqian1365
Cchenqian1365
6月11日 将 chenqian1365 设为负责人
夏国正
6月26日 issue类型由 任务 改变为 缺陷
CANN-robotCANN-robot成员
6月27日 从 cann/ge 转移
ykl999
ykl999成员
6月29日 评论:
likedislike
CANN-robotCANN-robot成员
6月29日 将 duanpengliang 设为负责人
duanpengliang
duanpengliang成员
6月29日 评论:

初定定位为引用计数异常,导致缓存数据无法被释放,正在解决中

likedislike
duanpengliang
duanpengliang成员
7月2日 评论:

image.png 问题已解决

likedislike
duanpengliangduanpengliang成员
7月2日 issue状态由 待办的 改变为 已完成
此处折叠了5条事件消息 查看更多
duanpengliangduanpengliang成员
7月2日 关闭了 issue