环境: .NET4.0,,Windows 7 (x64),VS2010。
下面是用于测试类的代码片段,它使用GC句柄来用GC.Collet()锁定对象。我有两个方法,如"Method1“和"Method2”。我想知道在GC句柄确定对象时,GC.Collect()使用哪一个是正确的。
代码片段:
class Test()
{
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
private GCHandle pinnedArray;
public GCHandle PinnedArray
{
get { lock (this) { return pinnedArray; } }
set { lock (this) { pinnedArray = value; } }
}
IntPtr pointer;
public IntPtr Pointer
{
get { lock (this) { return pointer; } }
set { lock (this) { pointer = value; } }
}
public instance()
{
const int size = 1024 * 768;
byte[] byteArray = null;
byteArray = new byte[size];
GCHandle PinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr Pointer = PinnedArray.AddrOfPinnedObject();
}
public void Method1(ref IntPtr ImageBuffer )
{
try
{
unsafe
{
if (ImageBuffer != IntPtr.Zero)
{
if (Pointer != null)
{
CopyMemory(Pointer, ImageBuffer, ImageSize);
// do stuff
//
m_numAcqs++;
if (m_numAcqs > _numMaxAcqs)
{
GC.Collect();
m_numAcqs = 0;
}
}
}
}
}
catch (Exception ex)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured : MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
return;
}
public void Method2(ref IntPtr ImageBuffer )
{
try
{
unsafe
{
if (ImageBuffer != IntPtr.Zero)
{
if (Pointer != null)
{
CopyMemory(Pointer, ImageBuffer, ImageSize);
// do stuff
//
}
}
}
m_numAcqs++;
if (m_numAcqs > _numMaxAcqs)
{
GC.Collect();
m_numAcqs = 0;
}
}
catch (Exception ex)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured : MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
return;
}
public close()
{
PinnedArray.free();
}
}编辑的问题:为不明确的问题道歉。我为我的问题附加了真正的密码。我有System.AccessViolationException错误。我有用于处理新图像的回调方法。这是代码片段。推荐采用Marshal.Copy方法。然而,如果我使用这种方法,系统的速度很慢。
// Local callback function used for handle new images
void HandleImage(ref Jai_FactoryWrapper.ImageInfo ImageInfo)
{
// Jai_FactoryWrapper.EFactoryError error = Jai_FactoryWrapper.EFactoryError.Success;
// This is in fact a callback, so we would need to handle the data as fast as possible and the frame buffer
// we get as a parameter will be recycled when we terminate.
// This leaves us with two choises:
// 1) Get the work we need to do done ASAP and return
// 2) Make a copy of the image data and process this afterwards
//
// We have the access to the buffer directly via the ImageInfo.ImageBuffer variable
//
// We can access the raw frame buffer bytes if we use "unsafe" code and pointer
// To do this we need to set the "Allow unsafe code" in the project properties and then access the data like:
//
// unsafe
// {
// // Cast IntPtr to pointer to byte
// byte* pArray = (byte*)ImageInfo.ImageBuffer;
// // Do something with the data
// // Read values
// byte value = pArray[10];
// // Write values
// for (int i = 0; i < 1000; i++)
// pArray[i] = (byte)(i % 255);
// }
// If we want to copy the data instead we can do like this without Unsafe code:
byte[] array = null;
if (ImageInfo.ImageBuffer != IntPtr.Zero)
{
// Allocate byte array that can contain the copy of data
array = new byte[ImageInfo.ImageSize];
IntPtr memoryDest = Marshal.AllocHGlobal((int)ImageInfo.ImageSize);
// Do the copying
Marshal.Copy(ImageInfo.ImageBuffer, array, 0, (int)ImageInfo.ImageSize);
Marshal.Copy(array, 0, memoryDest , (int)ImageInfo.ImageSize);
// Do something with the raw data
CopyToCogBuffer(memoryDest);
}
return;
}
private void CopyToCogBuffer(IntPtr pointer)
{
try
{
ICogImage8RootBuffer CogBuffer = new CogImage8Root();
CogBuffer.Initialize(int.Parse(myWidthNode.Value.ToString()), int.Parse(myHeightNode.Value.ToString()), pointer, int.Parse(myWidthNode.Value.ToString()), null);
if (CogBuffer != null)
{
CogImage8Grey pImage1 = new CogImage8Grey();
CogImage8Grey pImage2 = new CogImage8Grey();
pImage1.SetRoot(CogBuffer);
pImage2 = pImage1.Copy(CogImageCopyModeConstants.CopyPixels);
PImage = pImage2;
_numLiveDisplay++;
if (_numLiveDisplay > _numMaxLiveDisplay)
{
if (_liveProcessing)
{
if (CogDisplay != null)
CogDisplay.Image = (CogImage8Grey)pImage2;
m_numAcqs++;
if (m_numAcqs > _numMaxAcqs)
{
GC.Collect();
m_numAcqs = 0;
}
}
_numLiveDisplay = 0;
}
}
}
catch (CogException ex)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured : MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
catch (Exception ex)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured : MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
}所以我改变了把物体固定下来。如果我使用Kernel32.dll的"CopyMemory“方法,速度是非常快的。然而,随机出现了"System.AccessViolationException“。我想知道GCHandle PinnedArray是否正确使用。
private void HandleImage(ref Jai_FactoryWrapper.ImageInfo ImageInfo)
{
try
{
if (recipe.CameraInfo[indexID].Use)
{
byte[] byteArray = null;
if (ImageInfo.ImageBuffer != IntPtr.Zero)
{
// Allocate byte array that can contain the copy of data
byteArray = new byte[ImageInfo.ImageSize];
GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
CopyMemory(pointer, ImageInfo.ImageBuffer, ImageInfo.ImageSize);
CopyToCogBuffer(pointer);
pinnedArray.Free();
}
}
}
catch (Exception ex)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured : MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
return;
}这是来自EventViewer的调用堆栈信息。
Application Program : ImageDelegateSample.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
Stack :
at: Cognex.VisionPro.CogImage8Grey.Copy(Cognex.VisionPro.CogImageCopyModeConstants)
at: ImageDelegateSample.ClientManager.CopyToCogBuffer(IntPtr)
at: ImageDelegateSample.ClientManager.HandleImage(ImageInfo ByRef)
at: Jai_FactoryDotNET.CCamera.HandleImage(ImageInfo ByRef)
at: Jai_FactoryDotNET.CCamera+StreamWork.StreamThread()
at: System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at: System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at: System.Threading.ThreadHelper.ThreadStart()发布于 2014-02-06 15:05:22
都不是。如果释放内存,您最好希望GC.Collect()做一些有意义的事情。两种方法都没有。如果它需要去任何地方,非常不清楚为什么,那么它应该在关闭()方法。将byteArray设置为null之后。
这段代码很危险,它让人很容易忘记调用close()并严重泄漏内存。这也解释了为什么你认为你需要写这段代码。它解决不了这个问题,需要一次性的模式。终结器可以保证您不会忘记解除数组,Dispose()方法可以帮助您陷入using语句成功的陷阱。
CopyMemory()调用也非常危险,没有检查ImageSize <=大小,也没有检查图像格式。1024 * 768不足以存储1024x768位图,像素通常需要3或4个字节。堆损坏很难调试。始终支持Marshal.Copy(),它不允许破坏GC堆。它的另一个优点是它不需要固定数组。
https://stackoverflow.com/questions/21602685
复制相似问题