c#关于非托管内存的释放问题及解读

 更新时间:2023年02月26日 13:36:05   作者:云大圣  
这篇文章主要介绍了c#关于非托管内存的释放问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

关于非托管内存的释放问题

硬件:大华sdk

软件平台:win10+vs2015

背景:近期在做大华工业相机SDK的采集的时候,用到Marshal.copy,将托管的代码转换成非托管的指针内存,由于没有及时释放内存指针,导致pc的内存一直上涨,通过查看代码之后发现是因为内存指针的原因,所以使用 Marshal.FreeHGlobal(pData);去释放了托管的内存指针,在循环运行的时候才没有导致内存上涨,并且通过这此的测试,发现在循环采集的过程中,将RGB的格式转换成Hobject,Hobject类型的iamge图像可以不去dispose,不会导致内存溢出,这个和我之前的认知是有些不一样的,原先在循环采集的过程中,我都会去dispose,并且防止释放的不干净还会用gc.collet,但是现在测试之后发现不去释放也可以,所以就没有去释放,这样一来就方便我对内存里面的数据进行提取了,而不用去担心被dispose了。

托管内存与非托管内存之间的转换

c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存,然而c#毕竟运行在c++之上,有的时候,(比如可能我们需要引入一些第三方的c++或native代码的库,在Unity3d开发中很常见)我们需要直接在c#中操纵非托管的代码,这些non-managed memory我们就需要自己去处理他们的申请和释放了, c# 中提供了一些接口,完成托管和非托管之间的转换,以及对这部分内存的操作。

基本上有以下几种:

1.managed memory-> unmanaged memory

比如在c#中调用第三方的某个c++库,库中有个函数是void func(float * data, int length).我们需要传入给data的就应该是一个非托管的代码(why?首先传入托管的内存,c#层很可能会把它gc掉,而c++还在使用,而且托管的mem它的指针地址可能会发生改变,因此直接传给c++可能拿到的地址是错误的)

代码如下:

using System.Runtime.InteropServices;
float[] _managed_data  =... // this is the c# managed data
GCHandle unmanaged_data_handle = GCHandle.Alloc(_managed_data, GCHandleType.Pinned); //这里将标记_managed_data暂时不能被gc回收,并且固定对象的地址
func(unmanaged_data_handle.AddrOfPinnedObject(),_managed_data.Length);//这里将拿到非托管内存的固定地址,传给c++
unmanaged_data_handle.Free();//使用完毕后,将其handle free,这样c#可以正常gc这块内存

2.un-managed memory->managed memory

在c++中返回一个un-managed mem给c#使用。

有时需要在c++中分配一块处理好的内存,然后返回给c#来使用,如c++中某个接口 int func(int** data) (注意这里要使用指针的指针,因为data是得到的结果)

IntPtr unmanaged_ptr=IntPtr.Zero; //定义这个c#中用来接收c++返回数据的指针类型
int length = func(out unmanaged_ptr );//调用c++的函数,使unmanaged_ptr指向c++里分配的内存,注意这里用out ,才能与c++里面的**匹配。
byte[] managed_data = new byte[length];
Marshal.Copy(unmanaged_ptr, managed_data, 0, length);//将非托管内存拷贝成托管内存,才能在c#里面使用
Marshal.FreeHGlobal(unmanaged_ptr);//释放非托管的内存

3.在c#直接申请一个un-managed mem传给c++

有时需要直接在c#开辟一块非托管的内存,传给c++用,这块内存同样可以在c#中用后销毁。

代码如下

IntPtr unmanaged_data_prt = Marshal. AllocHGlobal(100);// 直接分配100 byte的内存
func(unmanaged_data_prt);//传给c++使用
Marshal.FreeHGlobal(unmanaged_data_prt);使用后销毁非托管内存

此外 Marshal类里面还有很多处理非托管内存的方法。

备注

托管内存和非托管内存在c#里面可以互相自由的转化,主要通过Marshal类和GCHandle类,编程时只要注意非托管的内存一定要负责好释放就可以了。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • C#结合JavaScript实现秒杀倒计时的方法

    C#结合JavaScript实现秒杀倒计时的方法

    这篇文章主要介绍了C#结合JavaScript实现秒杀倒计时的方法,涉及C#结合javascript操作时间的技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • C#中System.Text.Json匿名对象反序列化

    C#中System.Text.Json匿名对象反序列化

    这篇文章主要介绍了System.Text.Json匿名对象反序列化,下文代码基于. NET 6,为了代码整洁,实际配置了PropertyNameCaseInsensitive = true,本文结合实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • C#实现将RTF转为HTML的示例代码

    C#实现将RTF转为HTML的示例代码

    RTF文档即富文本格式(Rich Text Format)的文档。我们在处理文件时,遇到需要对文档格式进行转换时,可以将RTF转为其他格式,如转为DOCX/DOC、PDF或者HTML。本文将利用C#实现RTF转HTML,需要的可以参考一下
    2022-04-04
  • C#/.net程序调用Python的教程分享

    C#/.net程序调用Python的教程分享

    C#的优势在于window下的开发,不仅功能强大而且开发周期短。而python则有众多的第三方库,可以避免自己造轮子,利用C#来做界面,而具体实现使用python来实现可以大大提高开发效率。本文介绍如何使用pythonnet来执行python脚本,希望对大家有所帮助
    2023-03-03
  • 详解C#如何实现树形图列表

    详解C#如何实现树形图列表

    这篇文章主要为大家详细介绍了如何利用C#实现树形图列表,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以了解一下
    2022-12-12
  • 使用C#中的Flags特性

    使用C#中的Flags特性

    这篇文章介绍了使用C#中的Flags特性,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • C# 8.0中的范围类型(Range Type)示例详解

    C# 8.0中的范围类型(Range Type)示例详解

    这篇文章主要给大家介绍了关于C# 8.0中范围类型(Range Type)的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-12-12
  • C#游戏开发之实现俄罗斯方块游戏

    C#游戏开发之实现俄罗斯方块游戏

    这篇文章主要为大家详细介绍了C#如何实现经典俄罗斯方块游戏,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-01-01
  • C#的this关键字的2种用法

    C#的this关键字的2种用法

    这篇文章主要给大家分享的是C#的this关键字的2种用法,在使用C#的过程中,发现this关键是比较少用的,但是在下面这二个场合下是必须要使用的,不使用它是解决不了问题。下面我们就来看看文章的具体内容吧
    2021-10-10
  • 介绍C# 泛型类在使用中约束

    介绍C# 泛型类在使用中约束

    这篇文章介绍了C# 泛型类在使用中约束,有需要的朋友可以参考一下
    2013-09-09

最新评论