使用指针指向托管内存,和使用句柄指向本地内存
2007-03-26 13:32
387 查看
在编写托管代码的过程中,往往需要利用非托管内存的简单分配删除的特性,例如想生成一个大对象,使用之后想马上释放,就很适合在非托管内存中建立这个大对象。建立后,在托管代码中,需要一个句柄能指向这个大对象的内存,如下图所示。
这个过程可以使用Marshal类的AllocHGlobal方法,这个方法使用 GlobalAlloc 从进程的非托管内存中分配内存,并操作非托管内存。
Marshal::AlloclHGlobal()
相反,我们有时也希望在托管内存中分配内存,并在本地内存的指针指向它。例如在编写托管代码时,需要使用原来的库函数。但是托管代码所分配的内存都在托管堆中,本地堆中的指针不能直接指向它,如上图所示。
这时可以使用GCHandle的Alloc方法,这个方法为指定的对象分配句柄。所支持的句柄有:
其中Pinned句柄就是pin_ptr,由于该内存地址不变,所以该句柄指向的托管内存不进行垃圾回收,可以与指针相互转换。
GCHandle::Alloc(object^ , GCHandleType::Pinned);
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);
在Form1_Paint()方法中绘制两个Bitmap:
Graphics ^g = e->Graphics;
g->DrawImageUnscaled(bitmap,Point(0,0));
g->DrawImageUnscaled(newbitmap,Point(m_nImageWidth+10,0));
以下是输出的结果
这个过程可以使用Marshal类的AllocHGlobal方法,这个方法使用 GlobalAlloc 从进程的非托管内存中分配内存,并操作非托管内存。
Marshal::AlloclHGlobal()
相反,我们有时也希望在托管内存中分配内存,并在本地内存的指针指向它。例如在编写托管代码时,需要使用原来的库函数。但是托管代码所分配的内存都在托管堆中,本地堆中的指针不能直接指向它,如上图所示。
这时可以使用GCHandle的Alloc方法,这个方法为指定的对象分配句柄。所支持的句柄有:
[align=left]Normal[/align] | [align=left]此句柄类型表示不透明句柄,这意味着无法通过此句柄解析固定对象的地址。可以使用此类型跟踪对象,并防止它被垃圾回收器回收。当非托管客户端持有对托管对象的唯一引用(从垃圾回收器检测不到该引用)时,此枚举成员很有用。 [/align] | |
[align=left]Pinned[/align] | [align=left]此句柄类型类似于 Normal,但允许使用固定对象的地址。这将防止垃圾回收器移动对象,因此将降低垃圾回收器的效率。使用 Free方法可尽快释放已分配的句柄。 [/align] | |
[align=left]Weak[/align] | [align=left]此句柄类型用于跟踪对象,但允许回收该对象。当回收某个对象时,GCHandle 的内容归零。在终结器运行之前,Weak 引用归零,因此即使终结器使该对象复活,Weak 引用仍然是归零的。 [/align] | |
[align=left]WeakTrackResurrection[/align] | [align=left]该句柄类型类似于 Weak,但如果对象在终结过程中复活,此句柄不归零。 [/align] |
GCHandle::Alloc(object^ , GCHandleType::Pinned);
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);
在Form1_Paint()方法中绘制两个Bitmap:
Graphics ^g = e->Graphics;
g->DrawImageUnscaled(bitmap,Point(0,0));
g->DrawImageUnscaled(newbitmap,Point(m_nImageWidth+10,0));
以下是输出的结果
相关文章推荐
- 内存句柄与指针的区别
- 建立一个数组,内存放5个学生的数据(学号、成绩),用指针指向数组首元素,输出1、3、5学生的数据
- 使用Git上传本地项目文件带代码托管平台
- 使用回溯函数打印函数指针指向的函数名
- 七.OC基础加强--1.内存管理 2.野指针,内存泄露 3.set方法的内存管理 4.@property参数 5.@class和循环retain的使用 6.NSString的内存管理
- linux c二级指针的内存分配和使用
- C语言之指针专题一:指针变量和指针所指向的内存空间是两个不同的概念
- 面向对象--多继承&派生类对象内存布局分析&各基类指针所指向的位置分析
- 使用typedef定义指向函数的指针
- 使用malloc分别分配2KB的空间,然后用realloc调整为6KB的内存空间,打印指针地址
- C语言指针使用不当带来的内存不可读
- 使用malloc分别分配2KB,6KB的内存空间,打印指针地址
- 使用malloc分别分配2KB,6KB的内存空间,打印指针地址
- Qt C++ 指向对象的指针与内存分配的问题分析
- Objective-C之foundation框架中的NSString的使用方法、指针基本用法、读取本地和远程文件
- char ** str的使用方法:动态内存分配-------二维指针
- 使用Git命令把本地项目上传到Github托管
- android LruCache的使用 (本地缓存+内存缓存)
- 使用指向指针的指针创建任意大小的二维数组