使用指针指向托管内存,和使用句柄指向本地内存

来源:互联网 发布:网络社区特点 编辑:程序博客网 时间: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^ );
 
下面代码使用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 ^= e->Graphics;
                    g
->DrawImageUnscaled(bitmap,Point(0,0
));
                    g
->DrawImageUnscaled(newbitmap,Point(m_nImageWidth+10,0
));
 

 

    以下是输出的结果