从c ++ dll到c#多次传递数据后,为什么我的程序停止?(没有错误信息) [英] Why does my program stop after passing data from c++ dll to c# several times? (There's no error message)
问题描述
我正在开发一个项目,该项目需要dll文件才能使用c#编写的另一个程序使用(我对C ++/C#的用法不是很熟悉).在完成dll文件的开发之后,我开始了其测试过程(多次在C#中运行dll的函数调用以确保其正常工作).我已经问过将数据从C ++传递到C#的方法
我曾经说过,如果发生内存损坏,程序将在非常正常的行停止(例如std :: cout<< ...).我认为我的情况类似于那句话...
这是我的代码结构...
<代码>//dll.hppextern"C" LIB_API无效推断(无符号字符* img_pointer,长data_len,cv :: Mat *& res,int& img_count,int& mat_type_size,双参数[2]);extern"C" LIB_API void clear_mem(cv :: Mat * res);//dll.cppLIB_API无效推断(无符号char * img_pointer,长data_len,cv :: Mat *& res,int& img_count,int& mat_type_size,双参数[2]){尝试{img_count = 8;mat_type_size = sizeof(cv :: Mat);res =新的cv :: Mat [img_count];cv :: Mat&img1 = res [0];cv :: Mat&img2 = res [1];cv :: Mat&img3 = res [2];cv :: Mat&img4 = res [3];cv :: Mat&img5 = res [4];cv :: Mat&img6 = res [5];cv :: Mat&img7 = res [6];cv :: Mat&img8 = res [7];//一些更新img1〜img8的过程std :: cout<<"res->"<<res<<std :: endl;std :: cout<<"=====完成推断过程=====>><<(std :: clock()-t_inf1)/(double)CLOCKS_PER_SEC<<"s"<<std :: endl;}捕获(const std :: runtime_error& re){std :: cerr<<"***运行时错误:"<<re.what()<<std :: endl;返回;}捕获(const std :: exception& ex){std :: cerr<<"***发生错误:"<<例如:what()<<std :: endl;返回;}抓住 (...){std :: cerr<<发生未知故障*** ...可能的内存损坏"<<std :: endl;返回;}}LIB_API void clear_mem(cv :: Mat * res){尝试{std :: cout<<>>在'clear_mem'中...."<<std :: endl;std :: cout<<"res in clear_mem->"<<res<<std :: endl;delete [] res;std :: cout<<>>完成删除res ...."<<std :: endl;}捕获(const std :: runtime_error& re){std :: cerr<<"***运行时错误:"<<re.what()<<std :: endl;返回;}捕获(const std :: exception& ex){std :: cerr<<"***发生错误:"<<例如:what()<<std :: endl;返回;}抓住 (...){std :: cerr<<发生未知故障*** ...可能的内存损坏"<<std :: endl;返回;}}//test.cs命名空间Test_Unet_Console{班级计划{[DllImport(@"D:\ Coco \ Code \ C_plus_plus \ unet_cpp_dll \ x64 \ Release \ unet_cpp_dll.dll"]]私有静态外部无效推断(byte [] img,long data_len,out IntPtr images,ref int img_count,out int mat_type_size,[In,MarshalAs(UnmanagedType.LPArray,SizeConst = 3)] double [] param);[DllImport(@"D:\ Coco \ Code \ C_plus_plus \ unet_cpp_dll \ x64 \ Release \ unet_cpp_dll.dll"]]私有静态外部无效init_inference();[DllImport(@"D:\ Coco \ Code \ C_plus_plus \ unet_cpp_dll \ x64 \ Release \ unet_cpp_dll.dll"]]私有静态外部无效clear_mem(IntPtr images);静态void Cppdll_inf(位图图像,out List< Mat> output_pic,double []参数,out IntPtr imgPtrs){Console.WriteLine("fmt之前");ImageFormat fmt =新的ImageFormat(image.RawFormat.Guid);Console.WriteLine("imageCodecInfo之前");var imageCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID == image.RawFormat.Guid);//这是针对未从磁盘读取图像并将其存储在内存中的情况(例如,图像来自相机或快照)如果(imageCodecInfo == null){fmt = ImageFormat.Jpeg;Console.WriteLine("C#-imageCodecInfo为null");}Console.WriteLine(之前的MemoryStream");使用(MemoryStream ms = new MemoryStream()){尝试{Console.WriteLine("C#-图像之前保存");image.Save(ms,fmt);Console.WriteLine("C#-完成图片.保存");byte [] image_byte_array = ms.ToArray();Console.WriteLine("C#-阅读完图片");int imgCount = 0;推断(image_byte_array,ms.Length,out var imgPtrs,ref imgCount,out var matTypeSize,param);output_pic =新的List< Mat>();为(int i = 0; i< imgCount; i ++){output_pic.Add(新Mat(IntPtr.Add(imgPtrs,i * matTypeSize)));}Console.WriteLine(完成从imgPtrs ....获得价值");}抓住(前例外){扔前}}}//我尝试将其添加到我的代码中,但这会导致一些错误(我没有记录...)静态void clear(){Console.WriteLine("start gc collect");GC.Collect();GC.WaitForPendingFinalizers();Console.WriteLine(完成gc清除收集");}静态无效的show_result(List< Mat> pic_list){为(int i = 0; i< pic_list.Count; i ++){Console.WriteLine(i);Cv2.ImShow("test",pic_list [i]);Cv2.WaitKey(500);}Cv2.DestroyAllWindows();Console.WriteLine(完成显示图片");}静态void Main(){位图image1 =新位图("C:\\ Users \\ Coco \\ Desktop \\(3).png");double [] param = {0.7,20};//{VI_threshold,area_threshold}Console.WriteLine(>>>从C#初始化========);init_inference();//>>模型初始化Console.WriteLine(>>>从C#完成初始化======");对于(int i = 0; i< 3; i ++){Console.WriteLine(i);List< Mat>结果;IntPtr imgPtrs;Cppdll_inf(image1,out result,param,out imgPtrs);复制代码//图片推断Console.WriteLine(>>>完成image1 C#======");show_result(结果);//显示图片以检查结果是否正确clear_mem(imgPtrs);//清理从dll发送的内存(?result.Clear();Console.WriteLine(>>>完成结果.Clear()======");Console.WriteLine("==============================);}}}}
我尝试不将结果从dll返回到C#,它可以运行大约100次(我测试过的最大值).所以我认为问题可能出在将数据从dll传递到C#时的过程...
顺便说一下,这是我运行程序时的内存使用情况...
我已经在互联网上搜索了许多信息,但是我仍然不知道如何解决此问题,因此,非常感谢任何建议或帮助!
(感谢您阅读完我凌乱的问题描述!)
很久以来,没有记录这个问题的答案...
有两种处理方式(以我的经验):
- 通过在cpp中执行
delete [] cv :: Mat *
添加功能,每次从dll收到Mat *
后调用此函数> - 在C#的DLL函数调用中使用 IDisposable类 li>
(想象一下,每次使用此语法运行后,它都会自行杀死)
(这是中文资料,但我认为它的内容很清楚示例代码)
I'm working on a project which required a dll file for another program written in c# to use (I'm not very familiar with the usage of C++/C#). After finishing the development(?) of the dll file, I started its testing process(run the function call from dll in C# for many times to ensure it works fine). I've asked the way to pass data from C++ to C# here, and the problem is, the program will stop without any error message(I've put try catch in my program) after calling it over 2 times.
I've seen a saying that if there's a memory corruption, the program will stop at a very normal line(e.g. std::cout << ...). I think my situation is similar to that saying...
And here's my code structure...
//dll.hpp
extern "C" LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*& res, int& img_count, int& mat_type_size, double params[2]);
extern "C" LIB_API void clear_mem(cv::Mat* res);
//dll.cpp
LIB_API void inference(unsigned char* img_pointer, long data_len, cv::Mat*& res, int& img_count, int& mat_type_size, double params[2])
{
try
{
img_count = 8;
mat_type_size = sizeof(cv::Mat);
res = new cv::Mat[img_count];
cv::Mat& img1 = res[0];
cv::Mat& img2 = res[1];
cv::Mat& img3 = res[2];
cv::Mat& img4 = res[3];
cv::Mat& img5 = res[4];
cv::Mat& img6 = res[5];
cv::Mat& img7 = res[6];
cv::Mat& img8 = res[7];
//some process to update img1~img8
std::cout << "res->" << res << std::endl;
std::cout << "===== finish inference process ===== >> " << (std::clock() - t_inf1) / (double)CLOCKS_PER_SEC << " s" << std::endl;
}
catch (const std::runtime_error& re)
{
std::cerr << "*** Runtime error: " << re.what() << std::endl;
return;
}
catch (const std::exception& ex)
{
std::cerr << "*** Error occurred: " << ex.what() << std::endl;
return;
}
catch (...)
{
std::cerr << "*** Unknown failure occurred... Possible memory corruption" << std::endl;
return;
}
}
LIB_API void clear_mem(cv::Mat* res)
{
try
{
std::cout << ">> In 'clear_mem'...." << std::endl;
std::cout << "res in clear_mem->" << res << std::endl;
delete[] res;
std::cout << ">> finish deleting res...." << std::endl;
}
catch (const std::runtime_error& re)
{
std::cerr << "*** Runtime error: " << re.what() << std::endl;
return;
}
catch (const std::exception& ex)
{
std::cerr << "*** Error occurred: " << ex.what() << std::endl;
return;
}
catch (...)
{
std::cerr << "*** Unknown failure occurred... Possible memory corruption" << std::endl;
return;
}
}
//test.cs
namespace Test_Unet_Console
{
class Program
{
[DllImport(@"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
private static extern void inference(byte[] img, long data_len, out IntPtr images, ref int img_count, out int mat_type_size,
[In, MarshalAs(UnmanagedType.LPArray, SizeConst = 3)]double[] param);
[DllImport(@"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
private static extern void init_inference();
[DllImport(@"D:\Coco\Code\C_plus_plus\unet_cpp_dll\x64\Release\unet_cpp_dll.dll")]
private static extern void clear_mem(IntPtr images);
static void Cppdll_inf(Bitmap image, out List<Mat> output_pic, double[] param, out IntPtr imgPtrs)
{
Console.WriteLine("before fmt");
ImageFormat fmt = new ImageFormat(image.RawFormat.Guid);
Console.WriteLine("before imageCodecInfo");
var imageCodecInfo = ImageCodecInfo.GetImageEncoders().FirstOrDefault(codec => codec.FormatID == image.RawFormat.Guid);
//this is for situations, where the image is not read from disk, and is stored in the memory(e.g. image comes from a camera or snapshot)
if (imageCodecInfo == null)
{
fmt = ImageFormat.Jpeg;
Console.WriteLine("C# - imageCodecInfo is null");
}
Console.WriteLine("before MemoryStream");
using (MemoryStream ms = new MemoryStream())
{
try
{
Console.WriteLine("C# - before image.Save");
image.Save(ms, fmt);
Console.WriteLine("C# - finish image.Save");
byte[] image_byte_array = ms.ToArray();
Console.WriteLine("C# - finish reading pic");
int imgCount = 0;
inference(image_byte_array, ms.Length, out var imgPtrs, ref imgCount, out var matTypeSize, param);
output_pic = new List<Mat>();
for (int i = 0; i < imgCount; i++)
{
output_pic.Add(new Mat(IntPtr.Add(imgPtrs, i * matTypeSize)));
}
Console.WriteLine("finish getting value from imgPtrs.....");
}
catch (Exception ex)
{
throw ex;
}
}
}
// I've tried to add this in my code, but it will cause some error(I didn't record it...)
static void clear()
{
Console.WriteLine("start gc collect");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("finish gc collect in clear");
}
static void show_result(List<Mat> pic_list)
{
for (int i = 0; i < pic_list.Count; i++)
{
Console.WriteLine(i);
Cv2.ImShow("test", pic_list[i]);
Cv2.WaitKey(500);
}
Cv2.DestroyAllWindows();
Console.WriteLine("finish showing pic");
}
static void Main()
{
Bitmap image1 = new Bitmap("C:\\Users\\Coco\\Desktop\\(3).png");
double[] param = { 0.7, 20 }; //{ VI_threshold, area_threshold }
Console.WriteLine(">>> Initializing from C# =======");
init_inference(); // >> initialization of models
Console.WriteLine(">>> Finish initializing from C# ======");
for (int i = 0; i < 3; i++)
{
Console.WriteLine(i);
List<Mat> result;
IntPtr imgPtrs;
Cppdll_inf(image1, out result, param, out imgPtrs); // inference of picture
Console.WriteLine(">>> Finish image1 C# ======");
show_result(result); // showing pic to check if result is correct
clear_mem(imgPtrs); // clean the memory send from dll(?
result.Clear();
Console.WriteLine(">>> Finish result.Clear() ======");
Console.WriteLine("================================");
}
}
}
}
I've tried not to return the result from dll to C#, it can run about 100 times(the maximum I've tested). So I think the problem might be the process when passing data from dll to C#...
By the way, here's my memory usage when running the program...
I've searched many info on the internet, but I still have no idea how to fix this problem, so any advise or help is really appreciated!
(Thanks in advance for finish reading my messy question description! )
It's been quite long not recording the answer of this question...
There are two ways to handle this(in my experience):
- Adding a function with doing
delete[] cv::Mat*
in your cpp, call this function every time after you received aMat*
from dll - Using IDisposable Class in C#'s calling with DLL function
(Imagine like it kills itself after every run with this syntax)
(This is Chinese material, but I think it's pretty clear with its example code)
这篇关于从c ++ dll到c#多次传递数据后,为什么我的程序停止?(没有错误信息)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!