关于c#动态调用非托管DLL的内存释放问题

问题描述

本人由于客户的需要,需要在程序的运行过程中,动态加载不同的DLL。这与直接调用非托管DLL不一样。下面这个帖子中的第三个方法很好的说明了如何动态调用非托管DLL。http://blog.csdn.net/pansiom/article/details/568096#comments为了方便使用,我把文中的方法弄成了一个DLDApi类,如下usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Reflection;//使用Assembly类需用此命名空间usingSystem.Reflection.Emit;//使用ILGenerator需用此命名空间usingSystem.Runtime.InteropServices;//用DllImport需用此命名空间usingSystem.Text;namespaceCTP_ShiningMidas{publicclassDLDApi{///<summary>///参数传递方式枚举,ByValue表示值传递,ByRef表示址传递///</summary>publicenumModePass{ByValue=0x0001,ByRef=0x0002}///<summary>///原型是:HMODULELoadLibrary(LPCTSTRlpFileName);///</summary>///<paramname="lpFileName">DLL文件名</param>///<returns>函数库模块的句柄</returns>[DllImport("kernel32.dll")]staticexternIntPtrLoadLibrary(stringlpFileName);///<summary>///原型是:FARPROCGetProcAddress(HMODULEhModule,LPCWSTRlpProcName);///</summary>///<paramname="hModule">包含需调用函数的函数库模块的句柄</param>///<paramname="lpProcName">调用函数的名称</param>///<returns>函数指针</returns>[DllImport("kernel32.dll")]staticexternIntPtrGetProcAddress(IntPtrhModule,stringlpProcName);///<summary>///原型是:BOOLFreeLibrary(HMODULEhModule);///</summary>///<paramname="hModule">需释放的函数库模块的句柄</param>///<returns>是否已释放指定的Dll</returns>[DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)]staticexternboolFreeLibrary(IntPtrhModule);///<summary>///Loadlibrary返回的函数库模块的句柄///</summary>privateIntPtrhModule=IntPtr.Zero;///<summary>///GetProcAddress返回的函数指针///</summary>privateIntPtrfarProc=IntPtr.Zero;///<summary>///装载Dll///</summary>///<paramname="lpFileName">DLL文件名</param>publicvoidLoadDll(stringlpFileName){hModule=LoadLibrary(lpFileName);if(hModule==IntPtr.Zero){throw(newException("没有找到:"+lpFileName+"."));}}publicvoidLoadDll(IntPtrHMODULE){if(HMODULE==IntPtr.Zero){throw(newException("所传入的函数库模块的句柄HMODULE为空."));}hModule=HMODULE;}///<summary>///获得函数指针///</summary>///<paramname="lpProcName">调用函数的名称</param>publicvoidLoadFun(stringlpProcName){//若函数库模块的句柄为空,则抛出异常if(hModule==IntPtr.Zero){throw(newException("函数库模块的句柄为空,请确保已进行LoadDll操作!"));}//取得函数指针farProc=GetProcAddress(hModule,lpProcName);//若函数指针为空,则抛出异常if(farProc==IntPtr.Zero){throw(newException("没有找到:"+lpProcName+"这个函数的入口点"));}}///<summary>///获得函数指针///</summary>///<paramname="lpFileName">包含需调用函数的DLL文件名</param>///<paramname="lpProcName">调用函数的名称</param>publicvoidLoadFun(stringlpFileName,stringlpProcName){//取得函数库模块的句柄hModule=LoadLibrary(lpFileName);//若函数库模块的句柄为空,则抛出异常if(hModule==IntPtr.Zero){throw(newException("没有找到:"+lpFileName+"."));}//取得函数指针farProc=GetProcAddress(hModule,lpProcName);//若函数指针,则抛出异常if(farProc==IntPtr.Zero){throw(newException("没有找到:"+lpProcName+"这个函数的入口点"));}}///<summary>///卸载Dll///</summary>publicvoidUnLoadDll(){FreeLibrary(hModule);hModule=IntPtr.Zero;farProc=IntPtr.Zero;}///<summary>///调用所设定的函数///</summary>///<paramname="ObjArray_Parameter">实参</param>///<paramname="TypeArray_ParameterType">实参类型</param>///<paramname="ModePassArray_Parameter">实参传送方式</param>///<paramname="Type_Return">返回类型</param>///<returns>返回所调用函数的object</returns>publicobjectInvoke(object[]ObjArray_Parameter,Type[]TypeArray_ParameterType,ModePass[]ModePassArray_Parameter,TypeType_Return){//下面3个if是进行安全检查,若不能通过,则抛出异常if(hModule==IntPtr.Zero){throw(newException("函数库模块的句柄为空,请确保已进行LoadDll操作!"));}if(farProc==IntPtr.Zero){throw(newException("函数指针为空,请确保已进行LoadFun操作!"));}if(ObjArray_Parameter.Length!=ModePassArray_Parameter.Length){throw(newException("参数个数及其传递方式的个数不匹配."));}//下面是创建MyAssemblyName对象并设置其Name属性AssemblyNameMyAssemblyName=newAssemblyName();MyAssemblyName.Name="InvokeFun";//生成单模块配件AssemblyBuilderMyAssemblyBuilder=AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName,AssemblyBuilderAccess.Run);ModuleBuilderMyModuleBuilder=MyAssemblyBuilder.DefineDynamicModule("InvokeDll");//定义要调用的方法,方法名为“MyFun”,返回类型是“Type_Return”参数类型是“TypeArray_ParameterType”MethodBuilderMyMethodBuilder=MyModuleBuilder.DefineGlobalMethod("MyFun",MethodAttributes.Public|MethodAttributes.Static,Type_Return,TypeArray_ParameterType);//获取一个ILGenerator,用于发送所需的ILILGeneratorIL=MyMethodBuilder.GetILGenerator();for(inti=0;i<ObjArray_Parameter.Length;i++){//用循环将参数依次压入堆栈switch(ModePassArray_Parameter[i]){caseModePass.ByValue:IL.Emit(OpCodes.Ldarg,i);break;caseModePass.ByRef:IL.Emit(OpCodes.Ldarga,i);break;default:throw(newException("第"+(i+1).ToString()+"个参数没有给定正确的传递方式."));}}if(IntPtr.Size==4){//判断处理器类型IL.Emit(OpCodes.Ldc_I4,farProc.ToInt32());}elseif(IntPtr.Size==8){IL.Emit(OpCodes.Ldc_I8,farProc.ToInt64());}else{thrownewPlatformNotSupportedException();}IL.EmitCalli(OpCodes.Calli,CallingConvention.Cdecl,Type_Return,TypeArray_ParameterType);IL.Emit(OpCodes.Ret);//返回值MyModuleBuilder.CreateGlobalFunctions();//取得方法信息MethodInfoMyMethodInfo=MyModuleBuilder.GetMethod("MyFun");//Marshal.FreeHGlobal(MyAssemblyName);//Marshal.FreeHGlobal(MyAssemblyBuilder);//Marshal.FreeHGlobal(MyModuleBuilder);//Marshal.FreeHGlobal(MyMethodBuilder);//Marshal.FreeHGlobal(IL);//Marshal.FreeHGlobal(MyModuleBuilder);//Marshal.FreeHGlobal(MyMethodBuilder);returnMyMethodInfo.Invoke(null,ObjArray_Parameter);//调用方法,并返回其值}///<summary>///调用所设定的函数///</summary>///<paramname="IntPtr_Function">函数指针</param>///<paramname="ObjArray_Parameter">实参</param>///<paramname="TypeArray_ParameterType">实参类型</param>///<paramname="ModePassArray_Parameter">实参传送方式</param>///<paramname="Type_Return">返回类型</param>///<returns>返回所调用函数的object</returns>publicobjectInvoke(IntPtrIntPtr_Function,object[]ObjArray_Parameter,Type[]TypeArray_ParameterType,ModePass[]ModePassArray_Parameter,TypeType_Return){//下面2个if是进行安全检查,若不能通过,则抛出异常if(hModule==IntPtr.Zero){throw(newException("函数库模块的句柄为空,请确保已进行LoadDll操作!"));}if(IntPtr_Function==IntPtr.Zero){throw(newException("函数指针IntPtr_Function为空!"));}farProc=IntPtr_Function;returnInvoke(ObjArray_Parameter,TypeArray_ParameterType,ModePassArray_Parameter,Type_Return);}///<summary>///只要求函数名的DLL动态调用///</summary>///<paramname="funcName"></param>///<paramname="ObjArray_Parameter"></param>///<paramname="TypeArray_ParameterType"></param>///<paramname="ModePassArray_Parameter"></param>///<paramname="Type_Return"></param>///<returns></returns>publicobjectInvoke(stringfuncName,object[]ObjArray_Parameter,Type[]TypeArray_ParameterType,ModePass[]ModePassArray_Parameter,TypeType_Return){LoadFun(funcName);objectob=Invoke(ObjArray_Parameter,TypeArray_ParameterType,ModePassArray_Parameter,Type_Return);returnob;}}}

解决方案

本帖最后由 yuguangchan 于 2013-12-20 17:05:40 编辑
解决方案二:
[/code]使用上面这个类,就可以很轻松的加载Dll和使用Dll中的函数,如下:privateDLDApidynamicDll=newDLDApi();///声明动态DLL对象dynamicDll.LoadDll("Dll的地址");//加载dllprivatevoidDll_FreshDataSet(S_InfodataSet)//Dll刷入数据{object[]Parameters=newobject[]{dataSet};Type[]ParameterTypes=newType[]{typeof(S_Info)};DLDApi.ModePass[]themode=newDLDApi.ModePass[]{DLDApi.ModePass.ByValue};TypeType_Return=typeof(void);dynamicDll.Invoke("FreshDataSet",Parameters,ParameterTypes,themode,Type_Return);}

在使用的过程中,我会用上面这个类的方式先加载Dll,然后,通过上面的"只要求函数名的DLL动态调用函数"invoke多次调用DLL中的函数。整个过程都没有问题。执行结果也是正确的。但是,我发现,程序的内存变得越来越大。每次调用完函数之后,程序的内存都会变大一点。由于,我的程序需要调用Dll函数的次数是比较多的,最后,整个程序占用的内存会变到1G多。而如果我不用这种动态调用DLL的方式而采用正常的非托管DLL调用方式的话(本文一开始提到的文章中的(一)调用DLL中的非托管函数一般方法),内存则不会变大,调用也正常。但是,没有办法满足我动态调用DLL的需求。以上就是我所遇到的问题,即如果我用上述的动态调用非托管DLL的方法调用函数,内存会不断变大;而如果我不适用上述动态调用非托管DLL的方法,而是用一般调用DLL的方法,则内存不会变大,但是,满足不了我的需求。请大神不吝赐教!
解决方案三:
你在不停的编译新代码,当然越用内存越大。又回到老话题了,托管程序集没有卸载概念,自然无法释放。应用程序域有卸载的概念,所以想大量频繁动态编译就要放到一个应用程序域里面,用完之后卸载。
解决方案四:
引用2楼wddw1986的回复:

你在不停的编译新代码,当然越用内存越大。又回到老话题了,托管程序集没有卸载概念,自然无法释放。应用程序域有卸载的概念,所以想大量频繁动态编译就要放到一个应用程序域里面,用完之后卸载。

谢谢您的回复。但是,具体应该怎么释放呢?其实,我也并没有频繁的加载,我是只加载一次,然后,多次调用里面的函数,这样是否也会产生需要释放的东西?然后,如果要释放,应该怎么释放??程序中,我是这样子调用函数的privatevoidDll_FreshDataSet(S_InfodataSet)//Dll刷入数据{object[]Parameters=newobject[]{dataSet};Type[]ParameterTypes=newType[]{typeof(S_Info)};DLDApi.ModePass[]themode=newDLDApi.ModePass[]{DLDApi.ModePass.ByValue};TypeType_Return=typeof(void);dynamicDll.Invoke("FreshDataSet",Parameters,ParameterTypes,themode,Type_Return);}

上面的中间变量不是在出去这个域的时候就会自动被释放了吗?然后,如果是类里面的invoke函数有需要释放的东西的话,应该怎么释放呢??///<summary>///调用所设定的函数///</summary>///<paramname="ObjArray_Parameter">实参</param>///<paramname="TypeArray_ParameterType">实参类型</param>///<paramname="ModePassArray_Parameter">实参传送方式</param>///<paramname="Type_Return">返回类型</param>///<returns>返回所调用函数的object</returns>publicobjectInvoke(object[]ObjArray_Parameter,Type[]TypeArray_ParameterType,ModePass[]ModePassArray_Parameter,TypeType_Return){//下面3个if是进行安全检查,若不能通过,则抛出异常if(hModule==IntPtr.Zero){throw(newException("函数库模块的句柄为空,请确保已进行LoadDll操作!"));}if(farProc==IntPtr.Zero){throw(newException("函数指针为空,请确保已进行LoadFun操作!"));}if(ObjArray_Parameter.Length!=ModePassArray_Parameter.Length){throw(newException("参数个数及其传递方式的个数不匹配."));}//下面是创建MyAssemblyName对象并设置其Name属性AssemblyNameMyAssemblyName=newAssemblyName();MyAssemblyName.Name="InvokeFun";//生成单模块配件AssemblyBuilderMyAssemblyBuilder=AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName,AssemblyBuilderAccess.Run);ModuleBuilderMyModuleBuilder=MyAssemblyBuilder.DefineDynamicModule("InvokeDll");//定义要调用的方法,方法名为“MyFun”,返回类型是“Type_Return”参数类型是“TypeArray_ParameterType”MethodBuilderMyMethodBuilder=MyModuleBuilder.DefineGlobalMethod("MyFun",MethodAttributes.Public|MethodAttributes.Static,Type_Return,TypeArray_ParameterType);//获取一个ILGenerator,用于发送所需的ILILGeneratorIL=MyMethodBuilder.GetILGenerator();for(inti=0;i<ObjArray_Parameter.Length;i++){//用循环将参数依次压入堆栈switch(ModePassArray_Parameter[i]){caseModePass.ByValue:IL.Emit(OpCodes.Ldarg,i);break;caseModePass.ByRef:IL.Emit(OpCodes.Ldarga,i);break;default:throw(newException("第"+(i+1).ToString()+"个参数没有给定正确的传递方式."));}}if(IntPtr.Size==4){//判断处理器类型IL.Emit(OpCodes.Ldc_I4,farProc.ToInt32());}elseif(IntPtr.Size==8){IL.Emit(OpCodes.Ldc_I8,farProc.ToInt64());}else{thrownewPlatformNotSupportedException();}IL.EmitCalli(OpCodes.Calli,CallingConvention.Cdecl,Type_Return,TypeArray_ParameterType);IL.Emit(OpCodes.Ret);//返回值MyModuleBuilder.CreateGlobalFunctions();//取得方法信息MethodInfoMyMethodInfo=MyModuleBuilder.GetMethod("MyFun");returnMyMethodInfo.Invoke(null,ObjArray_Parameter);//调用方法,并返回其值}///<summary>///调用所设定的函数///</summary>///<paramname="IntPtr_Function">函数指针</param>///<paramname="ObjArray_Parameter">实参</param>///<paramname="TypeArray_ParameterType">实参类型</param>///<paramname="ModePassArray_Parameter">实参传送方式</param>///<paramname="Type_Return">返回类型</param>///<returns>返回所调用函数的object</returns>publicobjectInvoke(IntPtrIntPtr_Function,object[]ObjArray_Parameter,Type[]TypeArray_ParameterType,ModePass[]ModePassArray_Parameter,TypeType_Return){//下面2个if是进行安全检查,若不能通过,则抛出异常if(hModule==IntPtr.Zero){throw(newException("函数库模块的句柄为空,请确保已进行LoadDll操作!"));}if(IntPtr_Function==IntPtr.Zero){throw(newException("函数指针IntPtr_Function为空!"));}farProc=IntPtr_Function;returnInvoke(ObjArray_Parameter,TypeArray_ParameterType,ModePassArray_Parameter,Type_Return);}

我尝试了对这个函数里面的变量使用using这种方式,但是,VS说这些变量并不是可以depose的变量,不能使用using。。。
解决方案五:

解决方案六:
大概看了一下,提出我的想法,你可以用C语言写一个专门负责调用不同DLL方法的DLL假设就叫你的MyFun.DLL吧,里面有一个MyFunInvoke(参数。。。。)函数这个函数要负责解析上层传传入的参数,正确的对参数进行压栈,出栈,并调用正确的函数等。然后你可以在c#声明MyFun.DLL中的MyFunInvoke(参数。。。。)函数。所有的程序都使用C#中的方法,而不是即时的生成的相关的调用DLL。这样做好处是:你不会不断的动态生成DLL,造成内存不断增长。当然整个过程的难处在于MyFun.dll中的函数与C#中的函数参数如何进行设计,这里你可能需要实现PInvoke中一个自定义的数据封送处理器。来确保参数如何正确传递与返回。当然,如果有更简单的方法,请记得@我。
解决方案七:
谢谢你的回复,不过,我在使用上面的DLL的时候,并没有不断的生成DLL对象。我在使用的时候,仅NEW了一个DLL对象,也就是只会调用一次LoadLibrary(lpFileName)。我的内存的增加并不是因为我生成了新的对象,而是因为我不断通过这个对象调用函数。
解决方案八:
顶一个!!!!!
解决方案九:
非托管代码三种内存分配、释放方式:mallocfreenewdeleteCoTaskMemAllocCoTaskMemFree内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存,可以不用显示释放内存,net帮你搞定!而其他两种,net不支持的方式,必须还是由非托管方来释放!也就是:你要做C++和C#两边都封装一个相应的释放函数!
解决方案十:
我跟lz遇到了一摸一样的问题。不知lz找到解决办法没有?
解决方案十一:

解决方案十二:
确实类里面的invoke函数有需要释放的东西,下面是全部代码。publicclassGxInterface{privateILGeneratorm_IL;privateTypem_TypeReturn;privateType[]m_TypeArray_ParameterType;privateMethodInfom_MehtodInfo;///<summary>///参数传递方式枚举,ByValue表示值传递,ByRef表示址传递///</summary>publicenumModePass{ByValue=0x0001,ByRef=0x0002}///<summary>///原型是:HMODULELoadLibrary(LPCTSTRlpFileName);///</summary>///<paramname="lpFileName">DLL文件名</param>///<returns>函数库模块的句柄</returns>[DllImport("kernel32.dll")]staticexternIntPtrLoadLibrary(stringlpFileName);///<summary>///原型是:FARPROCGetProcAddress(HMODULEhModule,LPCWSTRlpProcName);///</summary>///<paramname="hModule">包含需调用函数的函数库模块的句柄</param>///<paramname="lpProcName">调用函数的名称</param>///<returns>函数指针</returns>[DllImport("kernel32.dll")]staticexternIntPtrGetProcAddress(IntPtrhModule,stringlpProcName);///<summary>///原型是:BOOLFreeLibrary(HMODULEhModule);///</summary>///<paramname="hModule">需释放的函数库模块的句柄</param>///<returns>是否已释放指定的Dll</returns>[DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)]staticexternboolFreeLibrary(IntPtrhModule);///<summary>///Loadlibrary返回的函数库模块的句柄///</summary>privateIntPtrhModule=IntPtr.Zero;///<summary>///GetProcAddress返回的函数指针///</summary>publicIntPtrfarProc=IntPtr.Zero;///<summary>///装载Dll///</summary>///<paramname="lpFileName">DLL文件名</param>publicvoidLoadDll(stringlpFileName){hModule=LoadLibrary(lpFileName);if(hModule==IntPtr.Zero){throw(newException("没有找到:"+lpFileName+"."));}}publicvoidLoadDll(IntPtrHMODULE){if(HMODULE==IntPtr.Zero){throw(newException("所传入的函数库模块的句柄HMODULE为空."));}hModule=HMODULE;}///<summary>///获得函数指针///</summary>///<paramname="lpProcName">调用函数的名称</param>publicvoidLoadFun(stringlpProcName){//若函数库模块的句柄为空,则抛出异常if(hModule==IntPtr.Zero){throw(newException("函数库模块的句柄为空,请确保已进行LoadDll操作!"));}//取得函数指针farProc=GetProcAddress(hModule,lpProcName);//若函数指针为空,则抛出异常if(farProc==IntPtr.Zero){throw(newException("没有找到:"+lpProcName+"这个函数的入口点"));}}///<summary>///获得函数指针///</summary>///<paramname="lpFileName">包含需调用函数的DLL文件名</param>///<paramname="lpProcName">调用函数的名称</param>publicvoidLoadFun(stringlpFileName,stringlpProcName){//取得函数库模块的句柄hModule=LoadLibrary(lpFileName);//若函数库模块的句柄为空,则抛出异常if(hModule==IntPtr.Zero){throw(newException("没有找到:"+lpFileName+"."));}//取得函数指针farProc=GetProcAddress(hModule,lpProcName);//若函数指针,则抛出异常if(farProc==IntPtr.Zero){throw(newException("没有找到:"+lpProcName+"这个函数的入口点"));}}///<summary>///卸载Dll///</summary>publicvoidUnLoadDll(){FreeLibrary(hModule);hModule=IntPtr.Zero;farProc=IntPtr.Zero;}publicvoidUnloadFun(){FreeLibrary(farProc);farProc=IntPtr.Zero;}///<summary>///调用所设定的函数///</summary>///<paramname="ObjArray_Parameter">实参</param>///<paramname="TypeArray_ParameterType">实参类型</param>///<paramname="ModePassArray_Parameter">实参传送方式</param>///<paramname="Type_Return">返回类型</param>///<returns>返回所调用函数的object</returns>publicobjectInvoke(object[]ObjArray_Parameter,Type[]TypeArray_ParameterType,ModePass[]ModePassArray_Parameter,TypeType_Return){//下面3个if是进行安全检查,若不能通过,则抛出异常if(hModule==IntPtr.Zero){throw(newException("函数库模块的句柄为空,请确保已进行LoadDll操作!"));}if(farProc==IntPtr.Zero){throw(newException("函数指针为空,请确保已进行LoadFun操作!"));}if(ObjArray_Parameter.Length!=ModePassArray_Parameter.Length){throw(newException("参数个数及其传递方式的个数不匹配."));}if(m_IL==null||Type_Return.FullName!=m_TypeReturn.FullName||!Equals(TypeArray_ParameterType,m_TypeArray_ParameterType)){//下面是创建MyAssemblyName对象并设置其Name属性AssemblyNameMyAssemblyName=newAssemblyName();MyAssemblyName.Name="InvokeFun";//生成单模块配件AssemblyBuilderMyAssemblyBuilder=AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName,AssemblyBuilderAccess.Run);ModuleBuilderMyModuleBuilder=MyAssemblyBuilder.DefineDynamicModule("InvokeDll");//定义要调用的方法,方法名为“MyFun”,返回类型是“Type_Return”参数类型是“TypeArray_ParameterType”MethodBuilderMyMethodBuilder=MyModuleBuilder.DefineGlobalMethod("MyFun",MethodAttributes.Public|MethodAttributes.Static,Type_Return,TypeArray_ParameterType);//获取一个ILGenerator,用于发送所需的ILm_IL=MyMethodBuilder.GetILGenerator();m_TypeReturn=Type_Return;m_TypeArray_ParameterType=TypeArray_ParameterType;for(inti=0;i<ObjArray_Parameter.Length;i++){//用循环将参数依次压入堆栈switch(ModePassArray_Parameter[i]){caseModePass.ByValue:m_IL.Emit(OpCodes.Ldarg,i);break;caseModePass.ByRef:m_IL.Emit(OpCodes.Ldarga,i);break;default:throw(newException("第"+(i+1).ToString()+"个参数没有给定正确的传递方式."));}}if(IntPtr.Size==4){//判断处理器类型m_IL.Emit(OpCodes.Ldc_I4,farProc.ToInt32());}elseif(IntPtr.Size==8){m_IL.Emit(OpCodes.Ldc_I8,farProc.ToInt64());}else{thrownewPlatformNotSupportedException();}m_IL.EmitCalli(OpCodes.Calli,CallingConvention.Cdecl,Type_Return,TypeArray_ParameterType);m_IL.Emit(OpCodes.Ret);//返回值MyModuleBuilder.CreateGlobalFunctions();m_MehtodInfo=MyModuleBuilder.GetMethod("MyFun");}//Marshal.FreeHGlobal(MyAssemblyName);//Marshal.FreeHGlobal(MyAssemblyBuilder);//Marshal.FreeHGlobal(MyModuleBuilder);//Marshal.FreeHGlobal(MyMethodBuilder);//Marshal.FreeHGlobal(IL);//Marshal.FreeHGlobal(MyModuleBuilder);//Marshal.FreeHGlobal(MyMethodBuilder);//取得方法信息returnm_MehtodInfo.Invoke(null,ObjArray_Parameter);//调用方法,并返回其值}privateboolEquals(Type[]typeList1,Type[]typeList2){if(typeList1.Length!=typeList2.Length){returnfalse;}for(varindex=0;index<typeList1.Length;index++){if(typeList1[index].FullName!=typeList2[index].FullName){returnfalse;}}returntrue;}}
解决方案十三:
帮顶,我也遇到这个问题。
解决方案十四:
可以使用缓存解决.
解决方案十五:
请问楼主最后解决了没?我也是遇到了相同的问题,虽然不是这样的调用方法,但是也是调用的dll,发现内存就会上涨。
解决方案:
Marshal::GetDelegateForFunctionPointer使用这个方法可以直接呼叫本地导出的方法。

时间: 2024-09-01 04:44:59

关于c#动态调用非托管DLL的内存释放问题的相关文章

非托管dll-C#调用非托管DLL,报“其他内存已损坏”,请问怎么解决呢?

问题描述 C#调用非托管DLL,报"其他内存已损坏",请问怎么解决呢? 定义: [DllImport("BSEncrypt.dll")] public static extern bool MD5String(ref string instr, int inlen, ref string outstr, int outlen); 调用: String ls_MD5Password = new String('', 100); string as_Password =

调用非托管dll常出现的bug及解决办法

C和C++有很多好的类库的沉淀,在.NET中,完全抛弃它们而重头再来是非常不明智的.也是不现实的,所以,我们经常需要通过Pinvoke来使用以前遗留下来的非托管的dll.就.NET中使用非托管的dll经验而言,经常碰到的问题至少有两个,它们都是通过在运行时抛出异常来体现的. 1.试图加载格式不正确的程序 出现这种异常,通常是.NET应用程序的"目标平台"与非托管dll的平台不一样. 一般,在使用VS开发.NET的应用程序和类库时,默认的目标平台为"Any CPU",

C#调用非托管DLL,窗口关闭后报错,求教!

问题描述 这几天在做一个医院的报销接口系统,对方提供的接口是一个DLL动态库,暂且叫做A.DLL,是delphi的.其中A.DLL中封装的各功能方法,我都能正常调用,也都执行正常,但是唯一一点不足的就是,有的时候我关闭浏览器(我们的系统是BS)的时候,就会弹出下面的那个错误提示:无效的窗口句柄.以前做此类报销接口的时候其他厂商也很多是非托管DLL,但是没有出现过此类情况.百度了很长时间,有的说资源释放问题,有的说是A.DLL自身没有做好处理,各种各样的方案吧.然后自己又写了一个CS的Demo来测

关于c#调用非托管dll的问题

问题描述 vc6中的定义如下:注册数据流直读取回调:RegisterStreamDirectReadCallback()函数:intRegisterStreamDirectReadCallback(STREAM_DIRECT_READ_CALLBACKStreamDirectReadCallback,void*Context)参数:STREAM_DIRECT_READ_CALLBACKStreamDirectReadCallback数据流准备好时会调用该函数Void*Context调用回调函数时

有关c# 调用vc++编写的非托管DLL、socket编程等相关知识的讲的比较详细的书籍

问题描述 有关c# 调用vc++编写的非托管DLL.socket编程等相关知识的讲的比较详细的书籍 学习c# 调用vc++编写的非托管DLL.socket编程等相关知识的讲的比较详细的书籍都有哪些?(最好是基于VS2008的) 解决方案 c#调用非托管C++生成的dllc# 调用 C++ 非托管 DllC#调用非托管dll 解决方案二: 这样一个知识点,最好是 Baidu/Google 查找来解决 书上的内容,没有网络上的丰富

c#调用dll-调用非托管dll中类的方法

问题描述 调用非托管dll中类的方法 如何用c#来调用c++生成的dll文件中的类的方法? 解决方案 重写为C#的类,否则没办法

asp.net C#调用托管DLL和非托管DLL文件的区别

asp教程.net c#调用托管dll和非托管dll文件的区别 托管dll文件,可以在dotnet环境通过 "添加引用" 的方式,直接把托管dll文件添加到项目中.然后通过 using  dll命名空间,来调用相应的dll对象 .     非托管dll文件,在dotnet环境应用时,通过 dllimport 调用.    c# 调用非托管dll文件.dll文件是用c语言编写的. 如下: 1:结构定义   rditag_t     rditag_t结构定义了测点的结构   typedef

C#调用非托管C++DLL中的函数接口

问题描述 C#调用非托管C++DLL中的函数接口(有生成的DLL文件和Lib文件)怎么引用?引用项添加不了 解决方案 解决方案二:使用DllImport,添加引用只能针对.NET控件或COM组件.解决方案三:DllImport具体搜p/Invokehttp://www.cnblogs.com/xuqiang/archive/2010/12/21/1953355.html解决方案四:C++DLL中的函数中还调用了openCV的函数,能说一下怎么整么?解决方案五:引用3楼qq_28744297的回复

在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解) 背景

背景       在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用.本篇文章将引导你快速理解这个调用的过程.   步骤 1. 创建一个CSharpInvokeCPP的解决方案:   2. 创建一个C++的动态库项目:   3. 在应用程序设置中,选择"DLL",其他按照默认选项: 最后点击完成,得到如图所示项目:       我们可以看到这里有一些文件,其中dllmain.c