UE4中调用OpenCV DNN模块释放std::vector内存触发访问违规错误
问题:UE4中调用OpenCV DNN模块触发内存访问冲突错误
环境与背景
使用UE4 4.27.2版本,通过OpenCV 4.5.5版本加载YOLO实现摄像头门检测。UE4的OpenCV插件可正常调用摄像头及执行基础图像处理算法,相关OpenCV代码已通过外部测试,迁移到UE4后使用DNN模块时触发内存错误。
错误信息
Exception thrown at 0x00007FFAFB82551B (UE4Editor-Core.dll) in UE4Editor-Win64-DebugGame.exe: 0xC0000005: Access violation writing location 0x0000000000000010.
最小复现代码
using namespace cv; using namespace std; vector<int> outLayers = vector<int>(); vector<String> layersNames = vector<String>(); void FindVerticesProcess() { // Line 1310 to 1339 VideoCapture cap; string srcPath = "E:\\project\\CornerDetector\\src\\"; String videoPath = srcPath + string("IMG_3436.mov"); String modelConfiguration = srcPath + string("yolo-fastest-1.1.cfg"); String modelWeights = srcPath + string("yolo-fastest-1.1_best.weights"); String classesFile = srcPath + string("yolo-fastest-1.1.names"); cv::dnn::Net doorNet; vector<string> classes; ifstream ifs(classesFile.c_str()); string line; while (getline(ifs, line)) { classes.push_back(line); } doorNet = cv::dnn::readNetFromDarknet(modelConfiguration, modelWeights); doorNet.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV); doorNet.setPreferableTarget(cv::dnn::DNN_TARGET_OPENCL); cap.open(videoPath); for (int i = 0; i < 6; i++) { Mat frame; cap.read(frame); Mat blob; cv::dnn::blobFromImage(frame, blob, 1 / 255.0, cv::Size(320, 320)); doorNet.setInput(blob); outLayers.resize(0); layersNames.resize(0); outLayers = doorNet.getUnconnectedOutLayers(); layersNames = doorNet.getLayerNames(); } }
调用栈信息
UE4Editor-Core.dll!00007ffafb82551b() Unknown UE4Editor-Core.dll!00007ffafb826a3e() Unknown UE4Editor-Core.dll!00007ffafb829eb3() Unknown UE4Editor-Core.dll!00007ffafb37893c() Unknown UE4Editor-OpenCV-Win64-DebugGame.dll!operator delete(void * Ptr, unsigned __int64 Size) Line 26 C++ [External Code] > UE4Editor-OpenCV-Win64-DebugGame.dll!FindVerticesProcess() Line 1338 C++ > UE4Editor-OpenCV-Win64-DebugGame.dll!FFindVertices::Run() Line 1412 C++ > [External Code]
现象总结
- 错误触发位置不固定,
doorNet.getUnconnectedOutLayers()和doorNet.getLayerNames()均可能触发,多数在首次循环触发,偶尔在第二、三次循环触发。 - 删除上述两行代码后,错误消失。
- 曾找到相似问题但未获得有效解决方案,因无法修改OpenCV原生方法的返回类型,需针对性修复。
修复方案
1. 统一内存分配器
UE4使用自定义内存分配器,而OpenCV默认使用系统分配器,跨模块释放内存会导致冲突。
- 编译OpenCV时,强制使用UE4的内存分配机制:添加编译宏
CV_USE_UE4_ALLOCATOR(若OpenCV支持),或手动替换OpenCV内存分配代码为UE4的FMemory::Malloc/FMemory::Free接口。 - 确保OpenCV库与UE4插件使用相同的CRT运行时:比如都使用Debug/Release版本的多线程DLL,避免静态CRT与动态CRT混合。
2. 将STL容器改为局部变量
全局的outLayers和layersNames会接收OpenCV分配内存的容器,赋值后跨模块释放内存引发冲突。修改为函数内局部变量:
void FindVerticesProcess() { // ... 原有代码 ... for (int i = 0; i < 6; i++) { Mat frame; cap.read(frame); Mat blob; cv::dnn::blobFromImage(frame, blob, 1 / 255.0, cv::Size(320, 320)); doorNet.setInput(blob); // 替换为局部变量,确保内存分配释放都在同一模块内 vector<int> outLayers = doorNet.getUnconnectedOutLayers(); vector<String> layersNames = doorNet.getLayerNames(); } }
3. 禁用OpenCL目标后端
DNN_TARGET_OPENCL的异步执行可能引发内存访问竞态,尤其是DebugGame模式下。暂时切换为CPU目标验证:
doorNet.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
4. 延长Net对象生命周期
doorNet作为函数局部变量,循环内频繁调用get方法可能导致内部资源引用计数异常。可将doorNet移到函数外(如类成员变量),或用智能指针管理,避免反复创建销毁引发的内存问题。
内容的提问来源于stack exchange,提问作者peter liu
相关产品推荐
相关产品推荐

