使用指针指向托管内存,和使用句柄指向本地内存
来源:互联网 发布:网络社区特点 编辑:程序博客网 时间:2024/04/26 19:13
在编写托管代码的过程中,往往需要利用非托管内存的简单分配删除的特性,例如想生成一个大对象,使用之后想马上释放,就很适合在非托管内存中建立这个大对象。建立后,在托管代码中,需要一个句柄能指向这个大对象的内存,如下图所示。
这个过程可以使用Marshal类的AllocHGlobal方法,这个方法使用 GlobalAlloc 从进程的非托管内存中分配内存,并操作非托管内存。
Marshal::AlloclHGlobal()
相反,我们有时也希望在托管内存中分配内存,并在本地内存的指针指向它。例如在编写托管代码时,需要使用原来的库函数。但是托管代码所分配的内存都在托管堆中,本地堆中的指针不能直接指向它,如上图所示。
这时可以使用GCHandle的Alloc方法,这个方法为指定的对象分配句柄。所支持的句柄有:
Normal
此句柄类型表示不透明句柄,这意味着无法通过此句柄解析固定对象的地址。可以使用此类型跟踪对象,并防止它被垃圾回收器回收。当非托管客户端持有对托管对象的唯一引用(从垃圾回收器检测不到该引用)时,此枚举成员很有用。
Pinned
此句柄类型类似于 Normal,但允许使用固定对象的地址。这将防止垃圾回收器移动对象,因此将降低垃圾回收器的效率。使用 Free方法可尽快释放已分配的句柄。
Weak
此句柄类型用于跟踪对象,但允许回收该对象。当回收某个对象时,GCHandle 的内容归零。在终结器运行之前,Weak 引用归零,因此即使终结器使该对象复活,Weak 引用仍然是归零的。
WeakTrackResurrection
该句柄类型类似于 Weak,但如果对象在终结过程中复活,此句柄不归零。
其中Pinned句柄就是pin_ptr,由于该内存地址不变,所以该句柄指向的托管内存不进行垃圾回收,可以与指针相互转换。
GCHandle::Alloc(object^ , GCHandleType::Pinned);
Pointer = Marshal::UnsafeAddrOfPinnedArrayElement(object^ );
Pointer = Marshal::UnsafeAddrOfPinnedArrayElement(object^ );
下面代码使用vs2005的C++/CLI语言进行了试验。首先新建两个数组,并对第一俄数组进行赋值,将该数组转化为指针后,调用IPP的图像处理操作,镜像操作。然后将结果保存在第二个数组中。最后将两个数组显示出来。
array<unsigned char>^ arraybyte = gcnew array<unsigned char>(m_nImageWidth*m_nImageWidth*3);
array<unsigned char>^ arraybyte2 = gcnew array<unsigned char>(m_nImageWidth*m_nImageWidth*3);
int tmp=0;
for(int i=0;i<m_nImageWidth*m_nImageWidth*3-2;i++)
...{
tmp = i%(m_nImageWidth*3);
if(tmp<50 && (i - tmp*m_nImageWidth*3<50*3))
...{
arraybyte[i] = 255;arraybyte[i+1] = 255;arraybyte[i+2] = 255;
}
}
GCHandle handle = GCHandle::Alloc(arraybyte, GCHandleType::Pinned);
IntPtr hundleimg = (IntPtr)Marshal::UnsafeAddrOfPinnedArrayElement(arraybyte,0);
bitmap = gcnew Bitmap(m_nImageWidth,m_nImageWidth,m_nImageWidth*3,PixelFormat::Format24bppRgb,hundleimg);
GCHandle handle2 = GCHandle::Alloc(arraybyte2, GCHandleType::Pinned);
IntPtr hundleimg2 = (IntPtr)Marshal::UnsafeAddrOfPinnedArrayElement(arraybyte2,0);
IppiSize size;
size.width = m_nImageWidth;
size.height = m_nImageWidth;
IppiRect rect;
rect.x = rect.y = 0;
rect.width = rect.height = m_nImageWidth;
ippiMirror_8u_C3R(
(const unsigned char*)hundleimg.ToPointer(),m_nImageWidth*3,
(unsigned char*)hundleimg2.ToPointer(),m_nImageWidth*3,
size,IppiAxis::ippAxsVertical);
newbitmap = gcnew Bitmap(m_nImageWidth,m_nImageWidth,m_nImageWidth*3,PixelFormat::Format24bppRgb,hundleimg2);
array<unsigned char>^ arraybyte2 = gcnew array<unsigned char>(m_nImageWidth*m_nImageWidth*3);
int tmp=0;
for(int i=0;i<m_nImageWidth*m_nImageWidth*3-2;i++)
...{
tmp = i%(m_nImageWidth*3);
if(tmp<50 && (i - tmp*m_nImageWidth*3<50*3))
...{
arraybyte[i] = 255;arraybyte[i+1] = 255;arraybyte[i+2] = 255;
}
}
GCHandle handle = GCHandle::Alloc(arraybyte, GCHandleType::Pinned);
IntPtr hundleimg = (IntPtr)Marshal::UnsafeAddrOfPinnedArrayElement(arraybyte,0);
bitmap = gcnew Bitmap(m_nImageWidth,m_nImageWidth,m_nImageWidth*3,PixelFormat::Format24bppRgb,hundleimg);
GCHandle handle2 = GCHandle::Alloc(arraybyte2, GCHandleType::Pinned);
IntPtr hundleimg2 = (IntPtr)Marshal::UnsafeAddrOfPinnedArrayElement(arraybyte2,0);
IppiSize size;
size.width = m_nImageWidth;
size.height = m_nImageWidth;
IppiRect rect;
rect.x = rect.y = 0;
rect.width = rect.height = m_nImageWidth;
ippiMirror_8u_C3R(
(const unsigned char*)hundleimg.ToPointer(),m_nImageWidth*3,
(unsigned char*)hundleimg2.ToPointer(),m_nImageWidth*3,
size,IppiAxis::ippAxsVertical);
newbitmap = gcnew Bitmap(m_nImageWidth,m_nImageWidth,m_nImageWidth*3,PixelFormat::Format24bppRgb,hundleimg2);
在Form1_Paint()方法中绘制两个Bitmap:
Graphics ^g = e->Graphics;
g->DrawImageUnscaled(bitmap,Point(0,0));
g->DrawImageUnscaled(newbitmap,Point(m_nImageWidth+10,0));
g->DrawImageUnscaled(bitmap,Point(0,0));
g->DrawImageUnscaled(newbitmap,Point(m_nImageWidth+10,0));
以下是输出的结果
- 使用指针指向托管内存,和使用句柄指向本地内存
- 使用指向指针的指针进行动态内存分配
- 指向指针的指针申请动态内存
- 动态分配内存和指向它的指针变量
- 使用指向函数的指针
- 内存篇之指向栈的指针
- realloc 减少指针指向的内存
- 警惕:return 指向栈内存的指针
- 函数返回指向内存的指针
- 内存篇之指向栈的指针
- 指针未指向合法的内存
- 二维数组和指向指针的指针 ,指针做形参做局部变量以及内存分配
- 关于野指针和空指针,以及空指针指向的内存
- 指向指针的指针的使用
- 指向指针的指针 char **使用技巧
- 为什么要使用指向指针的指针
- 指针变量 如果指向的这块内存空间 已经被系统回收,程序员是不能使用这块内存
- 指向的内存
- hibernate分页
- BAPI / RFC with Delphi(系列之七)--TBAPIControl使用BUS1001显示物料(Delphi源代码)
- owner和parent的区别
- Eclipse下JSP预览的详细流程
- ADL之UI初预览 ,AJAX
- 使用指针指向托管内存,和使用句柄指向本地内存
- ASP.NET生成静态页面实现方法
- 生成静态文件的新闻系统核心代码
- Open source-fantastic!
- 滚动条样式收集
- Asp.net 2.0 中将网站首页生成静态页的一个比较好的方法
- 在托管代码中释放托管和非托管资源
- BAPI / RFC with Delphi(系列之八)--TBAPIControl使用BUS2012建立PO(Delphi源代码)
- GridView使用竅門