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

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

问题描述

这可能不是一个措辞明确的问题,因为我不确定发生了什么,所以我不知道该如何直截了当地问.我正在尝试学习,我希望我能对此有所指导.感谢您对新手的耐心.

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.

似乎GCHandle一直在引用相同的内存?我不是真的通过更改手柄名称来制作新手柄吗?遗憾的长一段代码,但我只丢失.

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.

出了什么问题?

最令人困惑的是它正在工作,然后我更改了一些内容,但现在又无法返回工作版本,我以为我的代码与工作的代码相同.在某个地方设置一些?

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?

围绕该byte[]创建位图.只要您不介意在托管内存中固定byte[],就可以这样做(可以这样做一段时间,而在应用程序运行期间则不然,等等).但是,在下一行,您释放了指针!

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!

然后使用相同的byte[],对其进行修改,然后将其用于其他位图.轰,它仍然是相同的字节数组.两个位图具有相同的内容也就不足为奇了-您要求这样做.

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.

它有时起作用而有时却不起作用的原因是,如果GC不移动手柄,则两个位图都是正确的.但是,如果GC移动字节数组,则位图将无法调整-它们仍将指向内存中的相同位置(这现在是错误的).

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).

您必须了解的是GCHandle不会创建新对象.只要GCHandle存在,它只是指示GC不要弄乱物理位置(好吧,在虚拟内存中,但是...).如果要创建新对象,请执行byte[].Clone()之类的操作.但是,您仍然必须在位图的整个生命周期中都固定住该句柄,这通常是一个坏主意.相反,尝试以通常的方式创建位图,然后执行Bitmap.LockBits,然后使用Marshal.Copy将位图数组复制到位图的非托管内存中,这样就很好,相对安全了.

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);
}

这并不是最佳的代码性能(确实需要复制),但是唯一的替代方法是使用unsafe代码-考虑到您目前对代码的明显了解,您实际上不应该这样做.受管环境.如果使用不当,可能会导致一些令人讨厌的问题.无论如何,性能提升都可以忽略不计-在您采取不安全的方法之前,请先确定您是否真正在意.

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天全站免登陆