p-invoke中C++申请的内存能在C#中释放吗?

bzcode 2011-10-27 08:05:59
小弟遇到这样一个问题,在C++中申请了一段内存:char * pResult = new char[100];

然后把这个指针作为返回参数:return pResult;

在C#中使用intPtr和marshal接收到了这个参数。

请问用完之后能把这个内存释放掉吗?
...全文
350 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
baby393 2012-01-07
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 lizhibin11 的回复:]
引用 14 楼 sdl2005lyx 的回复:
AllocHGlobal和FreeHGlobal ,其实对应的Kernel32.DLL 中公开API函数LocalAlloc 和LocalFree ,

两边都必须成对使用。关于new 、malloc、LocalAlloc 跟它们的释放 delete、free、LocalFree 机制上都不一样,不能相互混用,这在MSDN和教科书都说的很清楚了……
[/Quote]

死要脸,误人子弟,鉴定完毕!
malloc返回的肯定就是HeapAlloc/LocalAlloc/GlobalAlloc的返回数值吗?它不可以是CRT的私有堆吗?
bzcode 2011-11-01
  • 打赏
  • 举报
回复
楼上讨论让我打开眼界,我最后还是觉得老老实实用C++来释放比较好。毕竟机制不同,无法得知最后到底有没有操作成功。

多谢各位,散分。
hhddzz 2011-10-27
  • 打赏
  • 举报
回复
不行,
MSDN上平台调用那里说得很清楚了,封送拆收器始终使用CoTaskMemAlloc分配内存,使用CoTaskMemFree释放内存。
换句话说,.NET只能释放由CoTaskMemAlloc分配的内存。
像你这个函数,如果托管方把返回值声明为string,会直接出运行时错误。因为你返回类型声明为string,封送拆收器就会自动去释放那块内存,但实际上它没法释放。
把返回类型声明为IntPtr,然后用Marshal类的方法来读,这个可以,但是读完之后没法释放。

解决办法很简单,把C++代码中的new换成CoTaskMemAlloc就行了
然后托管代码那边你可以直接把返回值声明为string了
冰天雪地 2011-10-27
  • 打赏
  • 举报
回复
要有 INTPTR的指针。
卧_槽 2011-10-27
  • 打赏
  • 举报
回复
可以释放,c#其实是调用c++的dll在控制内存。
lizhibin11 2011-10-27
  • 打赏
  • 举报
回复
可以释放,不论是用new还是malloc分配的,都可以用Marshal.FreeHGlobal释放。
mabaolin 2011-10-27
  • 打赏
  • 举报
回复
c#不会管c++的申请的内存。c++中释放掉吧。
黄亮 2011-10-27
  • 打赏
  • 举报
回复
c++的只能c++处理。
宝_爸 2011-10-27
  • 打赏
  • 举报
回复
宝_爸 2011-10-27
  • 打赏
  • 举报
回复
不行C#中没有办法free unmanagred的内存。
你可以再加个Free函数来释放内存。

sdl2005lyx 2011-10-27
  • 打赏
  • 举报
回复
综合lizhibin11和hhddzz,可以感觉到,lizhibin11有点钻牛角尖,用一种机制分配内存,却采用另一种机制机制释放内存,即使侥幸正确,“不排除会出不可预知的问题”和“有点瞎猫碰死耗子的感觉”。我估计lizhibin11平常自己也不会这么使用!

而hhddzz说的比较合理:开发走“正统”的。

就事论事,没有其他意思,呵呵。。。
hhddzz 2011-10-27
  • 打赏
  • 举报
回复
额,其实关键的问题是,用什么方法在哪里分配的,就要用什么对应的方法在那个地方释放。而new操作符呢,且不说各家的实现不同,仅仅是VC,你就不清楚它的实现。
这种情况下,你怎么释放它都不太合理,就算成功了都有点瞎猫碰死耗子的感觉。

据说(我没有研究过),VC的实现,new调用malloc,malloc使用HeapAlloc分配内存,而他使用的堆是运行库在初始化时创建的一个私有堆。那么在外部,你没有这个私有堆的句柄,就没办法对这个堆进行操作。

按照这种说法,我在C++里做过测试,用静态链接到运行库的方式编译一个dll,这个dll种的某个方法new一个C风格字符串返回。然后从另外一个C++程序中调用该方法,无法通过delete[]释放得到的指针。因为程序和dll包含了两套运行库实现,这两套实现使用着不同的私有堆。

而且这还是在你知道dll是使用new运算符的情况下都会出问题。如果不能确定那个指针是由new分配的,那就更不能直接就delete。

回到LZ这个话题上来说,你根本就不知道new里面到底是回事,讨论.NET能不能释放怎么释放根本就没意义。一个简单地处理方法就是直接认为不能释放由new分配的内存。

lizhibin11 2011-10-27
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 sdl2005lyx 的回复:]
AllocHGlobal和FreeHGlobal ,其实对应的Kernel32.DLL 中公开API函数LocalAlloc 和LocalFree ,

两边都必须成对使用。关于new 、malloc、LocalAlloc 跟它们的释放 delete、free、LocalFree 机制上都不一样,不能相互混用,这在MSDN和教科书都说的很清楚了。。。
[/Quote]
对数组来说,new和malloc分配后的内存布局包括头部都是一样的,可以混用。LocalAlloc的地址头部和malloc不同,释放是可以释放的,你那个128太小,我在回这个帖子之前就分配大内存测试过可以释放,但是不排除会出不可预知的问题。我回这个帖子,是因为发现回帖者非常武断地说不可以,而我认为有待研究。现在最终的问题实质就是LocalFree释放malloc分配的内存会有什么问题。
sdl2005lyx 2011-10-27
  • 打赏
  • 举报
回复
AllocHGlobal和FreeHGlobal ,其实对应的Kernel32.DLL 中公开API函数LocalAlloc 和LocalFree ,

两边都必须成对使用。关于new 、malloc、LocalAlloc 跟它们的释放 delete、free、LocalFree 机制上都不一样,不能相互混用,这在MSDN和教科书都说的很清楚了。。。
sdl2005lyx 2011-10-27
  • 打赏
  • 举报
回复
Marshal.FreeHGlobal释放的是Marshal.AllocHGlobal在net代码分配的内存!

看看这个:

char* GetString()
{
int size=128;

char* pBuffer=(char*)malloc(size);
if(NULL!=pBuffer)
{
strcpy(pBuffer,"string from malloc");
}

return pBuffer;
}


你自己测试一下:Marshal.FreeHGlobal能不能释放C++分配的内存!
lizhibin11 2011-10-27
  • 打赏
  • 举报
回复
楼上,我那个不是偷换概念,它起码说明一个问题,对于数组来说,并不是严格的new只能对应delete而不可以free。
那再看Marshal.FreeHGlobal源代码最终调用的是什么,reflector只能看到调用了localfree,不能确定是不是win32的localfree。那只能做个测试看看是不是可以释放了,测试下来似乎是可以释放,具体会不会有其他问题没办法确定。
当然dll中包括对应的释放函数,或者使用函数指针来调用c#的委托方法是最好的,这是正道。但就这个问题来说,上来就说不能释放是不是太武断了?起码可以研究一下Marshal.FreeHGlobal是真的释放了,还是看起来释放了但会出现其他问题。
sdl2005lyx 2011-10-27
  • 打赏
  • 举报
回复
不要偷换概念,我们讨论的是C#如何释放C++分配的内存!!!
lizhibin11 2011-10-27
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 sdl2005lyx 的回复:]
5楼完全不对!8楼说的合理!

非托管代码三种内存分配、释放方式:
malloc free
new delete
CoTaskMemAlloc CoTaskMemFree

内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存……
[/Quote]
那你的意思在c++中如果new一个数组,是绝对不可以用free来释放的了?非托管内存和垃圾回收有什么关系?
sdl2005lyx 2011-10-27
  • 打赏
  • 举报
回复
5楼完全不对!8楼说的合理!

非托管代码三种内存分配、释放方式:
malloc free
new delete
CoTaskMemAlloc CoTaskMemFree

内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存,可以不用显示释放内存,net帮你搞定!而其他两种,net不支持的方式,必须还是由非托管方来释放!也就是:你要做C++和C#两边都封装一个相应的释放函数!

110,561

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧