两种不同的GCHandle的引用在内存中同一数组 [英] Two Different GCHandle's refer to same array in memory

查看:313
本文介绍了两种不同的GCHandle的引用在内存中同一数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能不是一个精心措辞的问题,因为我不知道是什么happenning,所以我不知道如何提出尖锐它。我想学习,我希望我能得到这方面的一些方向。你有新手耐心AP preciated。

我有一块code的我正在修改。它显示的图像。我想修改图像,并在不同的窗口中显示它。我复制code所显示的图像,请修改,并显示修改后的图像为原始和修改图像。

看来的GCHandle保持指同一存储器?我不是真正改变手柄名称进行新的处理?很抱歉的那条长长的code的,但我只是失去了。

这是怎么回事了?

最令人困惑的是,这是工作,那么我改变了一些东西,现在不能回去工作版本,尽管我认为我的code是相同的工作之一。一些设置一些在哪里?

System.Runtime.InteropServices.GCHandle gch3 = System.Runtime.InteropServices.GCHandle.Alloc(缩放,System.Runtime。 InteropServices.GCHandleType.Pinned); INT间距= mImageWidth;
 如果(间距%4!= 0)
     节距=((节距/ 4)+1)* 4; System.Drawing.Bitmap位=新位图(mImageWidth,mImageHeight,俯仰,System.Drawing.Imaging.PixelFormat.Format8bppIndexed,gch3.AddrOfPinnedObject()); gch3.Free(); 如果(PAL == NULL)
     {
         System.Drawing.Imaging.ColorPalette CP = bitmap.Palette;
         对于(i = 0; I< cp.Entries.Length ++ I)
             {
                  cp.Entries [I] = Color.FromArgb(我,我,我);
             }         PAL = CP;
      }  bitmap.Palette = PAL;  FirstImageDisplay.Image =位图;  这里//第二图像
  对于(i = 0; I< frame.Length ++ I)
      缩放[I] =(字节)(5 *缩放[I]);  System.Runtime.InteropServices.GCHandle gch4 = System.Runtime.InteropServices.GCHandle.Alloc(缩放,System.Runtime.InteropServices.GCHandleType.Pinned);  INT pitch1 = mImageWidth;  如果(pitch1%4!= 0)
      pitch1 =((pitch1 / 4)+1)* 4;  System.Drawing.Bitmap bitmap2 =新位图(mImageWidth,mImageHeight,俯仰,System.Drawing.Imaging.PixelFormat.Format8bppIndexed,gch4.AddrOfPinnedObject());  gch4.Free();  如果(PAL == NULL)
      {
          System.Drawing.Imaging.ColorPalette CP = bitmap.Palette;          对于(i = 0; I< cp.Entries.Length ++ I)
              {
                 cp.Entries [I] = Color.FromArgb(我,我,我);
              }           PAL = CP;
      }  bitmap.Palette = PAL;
  SecondImageDisplay.Image =位图;
  //结束第二图像code


解决方案

你在做什么肯定是不安全的。你为什么做这个?是否有一个原因,你是如此的舒服离开安全的,可管理的环境?

位图是围绕创建的byte [] 。这是正常的,只要你不介意有一个固定字节[] 在托管内存(好一会儿,没有真正为应用程序等的时间)。然而,在非常下一行,你松开指针!

然后使用相同的字节[] ,修改它,并将其用于另一个位图。咚,它仍然是相同的字节数组。这并不奇怪,这两个位图具有相同的内容 - 你要的那种。

为什么它有时工作,有时它没有其理由是,如果手柄无法通过GC移动时,这两个位图将是正确的。但是,如果GC移动字节数组,位图都没有调整方式 - 他们仍将指向内存中的相同位置(也就是现在的错误)

您要明白什么是一个的GCHandle不创建一个新的对象。它只是指示GC不会与物理位置一塌糊涂(当然,在虚拟内存,但是......)只要存在的GCHandle。如果你想创建一个新的对象,像做字节[]。克隆()。不过,你仍然要必须有固定的位图,这通常是一个坏主意的全部生命周期的手柄。相反,尝试创建位图通常的方式,然后做 Bitmap.LockBits ,然后用 Marshal.Copy 复制位图阵位图的非托管内存,就大功告成了,不错,比较安全。

下面是说明了整个概念的code片断:

 字节[]数据=新的字节[320 * 200 * 1];位图BMP1 =新位图(320,200,
       System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
位图BMP2 =新位图(320,200,
       System.Drawing.Imaging.PixelFormat.Format8bppIndexed);VAR BDATA = bmp1.LockBits(新的Rectangle(新点(0,0),bmp1.Size)
                 ImageLockMode.WriteOnly,bmp1.PixelFormat);
尝试
{
    Marshal.Copy(数据,0,bdata.Scan0,data.Length);
}
最后
{
    bmp1.UnlockBits(BDATA);
}//做你的修改BDATA = bmp2.LockBits(新的Rectangle(新点(0,0),bmp2.Size)
             ImageLockMode.WriteOnly,bmp2.PixelFormat);
尝试
{
    Marshal.Copy(数据,0,bdata.Scan0,data.Length);
}
最后
{
    bmp2.UnlockBits(BDATA);
}

这是不是最好的code性能明智的(它确实需要一些复制),但唯一真正的选择是使用不安全 code - 这你真的不应该做,因为有关管理环境当前的知识明显。这可能会导致一些讨厌的问题,如果你没有正确使用它。在任何情况下,性能提升可能是完全可以忽略 - 看看你真正关心你去不安全的方式之前,

有关问题的更多信息以托管和非托管内存的工作的复杂性,你可以看看我的博客的 http://www.luaan.cz/2014/07/a-quick-introduction-to-managed-and.html 这是仍然是相当高的水平,但它说明了比这个答案对自己多。

This is probably not a well-phrased question, because I am not sure what is happenning, so i don't know how to ask it pointedly. I am trying to learn, and i hope i can get some direction on this. Your patience with a neophyte is appreciated.

I have a piece of code i am modifying. It displays an image. I want to modify the image, and display it in a different window. I copy the code that displays the image, do the modification, and it displays the modified image for both the original and modified images.

It seems GCHandle keeps referring to the same memory? Am i not really making a new handle by changing the handle name? Sorry for the long piece of code, but i am just lost.

What is going wrong?

Most perplexing is that it was working, then i changed something, and now can't get back to the working version, tho i think my code is the same as the one that worked. Some setting some where?

 System.Runtime.InteropServices.GCHandle gch3 = System.Runtime.InteropServices.GCHandle.Alloc(scaled, System.Runtime.InteropServices.GCHandleType.Pinned);

 int pitch = mImageWidth;
 if (pitch % 4 != 0)
     pitch = ((pitch / 4) + 1) * 4;

 System.Drawing.Bitmap bitmap = new Bitmap(mImageWidth, mImageHeight, pitch, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, gch3.AddrOfPinnedObject());

 gch3.Free();

 if (pal == null)
     {
         System.Drawing.Imaging.ColorPalette cp = bitmap.Palette;
         for (i = 0; i < cp.Entries.Length; ++i)
             {
                  cp.Entries[i] = Color.FromArgb(i, i, i);
             }

         pal = cp;
      }

  bitmap.Palette = pal;

  FirstImageDisplay.Image = bitmap;

  //second image here
  for (i = 0; i < frame.Length; ++i)
      scaled[i] = (byte)(.5 * scaled[i]);

  System.Runtime.InteropServices.GCHandle gch4 = System.Runtime.InteropServices.GCHandle.Alloc(scaled, System.Runtime.InteropServices.GCHandleType.Pinned);

  int pitch1 = mImageWidth;

  if (pitch1 % 4 != 0)
      pitch1 = ((pitch1 / 4) + 1) * 4;

  System.Drawing.Bitmap bitmap2 = new Bitmap(mImageWidth, mImageHeight, pitch, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, gch4.AddrOfPinnedObject());

  gch4.Free();

  if (pal == null)
      {
          System.Drawing.Imaging.ColorPalette cp = bitmap.Palette;

          for (i = 0; i < cp.Entries.Length; ++i)
              {
                 cp.Entries[i] = Color.FromArgb(i, i, i);
              }

           pal = cp;
      }

  bitmap.Palette = pal;
  SecondImageDisplay.Image = bitmap;
  //end second image code

解决方案

What you're doing definitely isn't safe. Why are you doing this? Is there a reason you're so comfortable leaving the safe, managed environment?

The bitmap is created around that byte[]. This is okay as long as you don't mind having a pinned byte[] in the managed memory (okay for a few moments, not really for the duration of the application etc.). However, on the very next line, you release the pointer!

Then you use the same byte[], modify it, and use it for another bitmap. Boom, it's still the same byte array. It shouldn't be surprising that both bitmaps have the same content - you asked for that.

The reason why it sometimes works and sometimes it doesn't is that if the handle isn't moved by the GC, both bitmaps will be correct. However, if the GC moves the byte array, the Bitmaps have no way of adjusting - they will still point to the same location in memory (which is now wrong).

What you have to understand is that a GCHandle doesn't create a new object. It just instructs the GC not to mess with the physical location (well, in virtual memory, but...) as long as the GCHandle exists. If you want to create a new object, do something like byte[].Clone(). However, you're still going to have to have the handle pinned for all the lifetime of the Bitmap, which is usually a bad idea. Instead, try creating the Bitmap the usual way, then doing Bitmap.LockBits, then use Marshal.Copy to copy the bitmap array to the unmanaged memory of the Bitmap, and you're done, nice and relatively safe.

Here's a code snippet that illustrates the whole concept:

byte[] data = new byte[320 * 200 * 1];

Bitmap bmp1 = new Bitmap(320, 200, 
       System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
Bitmap bmp2 = new Bitmap(320, 200, 
       System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

var bdata = bmp1.LockBits(new Rectangle(new Point(0, 0), bmp1.Size), 
                 ImageLockMode.WriteOnly, bmp1.PixelFormat);
try
{
    Marshal.Copy(data, 0, bdata.Scan0, data.Length);
}
finally
{
    bmp1.UnlockBits(bdata);
}

// Do your modifications

bdata = bmp2.LockBits(new Rectangle(new Point(0, 0), bmp2.Size), 
             ImageLockMode.WriteOnly, bmp2.PixelFormat);
try
{
    Marshal.Copy(data, 0, bdata.Scan0, data.Length);
}
finally
{
    bmp2.UnlockBits(bdata);
}

This isn't the best code performance-wise (it does need some copying), but the only real alternative is to use unsafe code - which you really shouldn't be doing, given your current apparent knowledge about the managed environment. It can lead to some nasty issues if you don't use it properly. In any case, the performance gains might be quite negligible - find out if you actually care before you go the unsafe way.

For more information about the problem and the complexities of working with managed and unmanaged memory, you can have a look at my blog at http://www.luaan.cz/2014/07/a-quick-introduction-to-managed-and.html It's still rather high-level, but it explains more than this answer on its own.

这篇关于两种不同的GCHandle的引用在内存中同一数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆