垃圾回收导致程序崩溃(GC.Collect crash)

jizhiguo 2009-10-22 08:24:27
垃圾回收导致程序崩溃(GC.Collect crash)

环境:
winxp(sp3),vs2005,.net 2.0,c#语言,oracle 10g

程序概述:
程序调用第三方提供的dll操作串口,控制串口上连接的设备(2个串口,分别使用2个厂商提供dll文件),在与串口通信的过程中,程序还通过TCP协议连接另一台主机,获取一些数据发给串口,同时,程序还通过oralce 10g客户端操作数据库服务器。程序在运行过程中,会向串口发送多次命令,每次发送一批(大概几十条,每条256字节以内)。每个命令就是一串字节数组写向串口。

问题描述:
向串口发送一批命令,程序在CLR执行垃圾回收时崩溃,直接弹系统错误对话框(就是发送错误报告的那个对话框),为了查找问题,我在每次向串口发送命令之前,都强制执行GC.Collect()来回收垃圾,发现每次都是到那条指令前执行GC.Collect()程序才崩溃。我用DebugDiag捕捉到dump文件,用WinDbg工具分析这个dump文件,具体分析结果如下,请哪位达人帮忙分析解答。谢谢!jizhiguo@netease.com

-------------WinDbg分析结果----------

Loading Dump File [D:\Program Files\DebugDiag\Logs\Misc\NSIISys.exe__PID__2456__Date__10_21_2009__Time_02_50_39PM__31__Manual Dump.dmp]
User Mini Dump File with Full Memory: Only application data is available

Comment: 'Dump created by Debug Diagnostic Tool'
Symbol search path is: SRV*d:\websymbols*http://msdl.microsoft.com/download/symbols;D:\jizg\NSIISys\bin\Debug;D:\Symbols
Executable search path is:
Windows XP Version 2600 (Service Pack 3) MP (2 procs) Free x86 compatible
Product: WinNt, suite: SingleUserTS Personal
Machine Name:
Debug session time: Wed Oct 21 14:50:39.000 2009 (GMT+8)
System Uptime: 0 days 3:33:01.279
Process Uptime: 0 days 0:01:24.000
................................................................
......................
Loading unloaded module list
.....
eax=015ca5ac ebx=013c3518 ecx=79308060 edx=0015b210 esi=01412b28 edi=015ca908
eip=7c92e514 esp=0013ecc0 ebp=0013ed54 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCallRet:
7c92e514 c3 ret
0:000> kbn
# ChildEBP RetAddr Args to Child
00 0013ecbc 77d19418 7b1d8ea8 09c75026 79e7a6e8 ntdll!KiFastSystemCallRet
*** WARNING: Unable to verify checksum for System.Windows.Forms.ni.dll
01 0013ed54 7b1d8997 00000000 00000004 00000000 user32!NtUserWaitMessage+0xc
02 0013edac 7b1d87e1 01466204 00000000 00000000 System_Windows_Forms_ni+0x208997
03 0013eddc 7b6ede2b 015b1034 01457990 000301c6 System_Windows_Forms_ni+0x2087e1
04 0013edf4 7b7225ab 09c75026 79e7a6e8 0013f0a8 System_Windows_Forms_ni+0x71de2b
05 0013ee80 7b7227c3 00e7bd99 0013f1f4 79edeff8 System_Windows_Forms_ni+0x7525ab
06 0013eed0 7b1e2d98 01442108 013dff40 013dfee0 System_Windows_Forms_ni+0x7527c3
07 0013eee8 7b88a746 014cd8d8 013dfee0 014cd8d8 System_Windows_Forms_ni+0x212d98
08 0013eefc 7b7467de 013dfee0 00000016 013dfee0 System_Windows_Forms_ni+0x8ba746
09 0013ef28 7b746e40 013dff40 014420ec 013dfee0 System_Windows_Forms_ni+0x7767de
0a 0013ef6c 7b746339 014cd8a4 013dfee0 0013ef94 System_Windows_Forms_ni+0x776e40
0b 0013ef7c 7ba34fcb 00000002 013dfee0 014cd8a4 System_Windows_Forms_ni+0x776339
0c 0013ef94 7b740cb6 00000002 0000000d 0000002a System_Windows_Forms_ni+0xa64fcb
0d 0013efc4 7b74a89d 09c75026 00000000 00000000 System_Windows_Forms_ni+0x770cb6
0e 0013f010 7b6f76f3 013f7af8 0000000f 000f002a System_Windows_Forms_ni+0x77a89d
0f 0013f094 7ba2a136 00000001 00100000 09c75026 System_Windows_Forms_ni+0x7276f3
10 0013f0f4 7b1d1dca 0015b210 0013f170 7b1f2051 System_Windows_Forms_ni+0xa5a136
11 0013f100 7b1f2051 09c75026 79e7a6e8 0013f338 System_Windows_Forms_ni+0x201dca
12 0013f170 7b1affc6 0013f1a8 013f7d24 0013f188 System_Windows_Forms_ni+0x222051
13 0013f180 7b1c86a0 0013f19c 7b1c8621 00000000 System_Windows_Forms_ni+0x1dffc6
0:000> .loadby sos mscorwks
0:000> !clrstack
OS Thread Id: 0xbb8 (0)
ESP EIP
0013eccc 7c92e514 [InlinedCallFrame: 0013eccc] System.Windows.Forms.UnsafeNativeMethods.WaitMessage()
0013ecc8 7b1d8ea8 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
0013ed64 7b1d8997 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
0013edb8 7b1d87e1 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
0013ede8 7b6ede2b System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form)
0013edfc 7b7225ab System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window)
0013ee88 7b7227c3 System.Windows.Forms.Form.ShowDialog()
0013ee8c 00e7bd99 NSIISys.FrmMain.自动发卡机ToolStripMenuItem1_Click(System.Object, System.EventArgs)
0013eedc 7b1e2d98 System.Windows.Forms.ToolStripItem.RaiseEvent(System.Object, System.EventArgs)
0013eef4 7b88a746 System.Windows.Forms.ToolStripMenuItem.OnClick(System.EventArgs)
0013ef04 7b7467de System.Windows.Forms.ToolStripItem.HandleClick(System.EventArgs)
0013ef30 7b746e40 System.Windows.Forms.ToolStripItem.HandleMouseUp(System.Windows.Forms.MouseEventArgs)
0013ef74 7b746339 System.Windows.Forms.ToolStripItem.FireEventInteractive(System.EventArgs, System.Windows.Forms.ToolStripItemEventType)
0013ef88 7ba34fcb System.Windows.Forms.ToolStripItem.FireEvent(System.EventArgs, System.Windows.Forms.ToolStripItemEventType)
0013efa0 7b740cb6 System.Windows.Forms.ToolStrip.OnMouseUp(System.Windows.Forms.MouseEventArgs)
0013efcc 7b74a89d System.Windows.Forms.ToolStripDropDown.OnMouseUp(System.Windows.Forms.MouseEventArgs)
0013f018 7b6f76f3 System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef, System.Windows.Forms.MouseButtons, Int32)
0013f0a4 7ba2a136 System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)
0013f0a8 7b1d1dca [InlinedCallFrame: 0013f0a8]
0013f108 7b1f2051 System.Windows.Forms.ToolStrip.WndProc(System.Windows.Forms.Message ByRef)
0013f10c 7b1affc6 [InlinedCallFrame: 0013f10c]
0013f188 7b1c86a0 System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms.Message ByRef)
0013f190 7b1c8621 System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)
0013f1a4 7b1c84fa System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
0013f338 003b20a4 [NDirectMethodFrameStandalone: 0013f338] System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
0013f348 7b1d8d2e System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
0013f3e4 7b1d8997 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
0013f438 7b1d87e1 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
0013f468 7b195931 System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
0013f47c 00e700ae NSIISys.Program.Main()
0013f69c 79e71b4c [GCFrame: 0013f69c]
...全文
1066 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
lextm 2010-09-18
  • 打赏
  • 举报
回复
ls不懂得就不要装懂。没听说Windows XP SP2不能用GC.Collect。

至于lz,看dump的水平太差。搞不定的就联系微软技术支持帮你看看dump吧,http://support.microsoft.com。

GC.Collect出异常一般都是你代码里面释放非托管资源的代码太烂,导致内存访问错误一类。当然,也可能是其他编码问题,和.NET自身都没什么关系。
CGabriel 2010-09-17
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 directray 的回复:]
无语了。。。我也遇到了这个问题。经过细心查证,发现是因为GC的Collect方法不支持XP SP3...
不信的可以去MSDN上查一下GC,然后看看支持的平台列表。不管哪个版本都没有对XP SP3提供支持。
[/Quote]

Platforms 的列表里面还没有 windows 98 SE 呢, 结果还不是好好的? 也没有 windows 2008,更没有 windows 2008 R2....是不是就不能用了呢?

Windows XP SP3 都已经被事实证明了无数次是没有问题的
DirectRay 2010-09-17
  • 打赏
  • 举报
回复
无语了。。。我也遇到了这个问题。经过细心查证,发现是因为GC的Collect方法不支持XP SP3...
不信的可以去MSDN上查一下GC,然后看看支持的平台列表。不管哪个版本都没有对XP SP3提供支持。
jizhiguo 2009-10-25
  • 打赏
  • 举报
回复
没有什么通信组件,只是利用C#的SerialPort类而已。代码就这点,如下:



using System;
using System.Collections.Generic;
using System.Text;
using SysUtilities;

namespace IFDMgr
{
public class SerialPortMgr : IIFDMgr
{
private System.IO.Ports.SerialPort serialPort = null;
private int sequence = 0;//执行指令的序列号,0~7循环取值

public SerialPortMgr(string port)
{
this.serialPort = new System.IO.Ports.SerialPort(port);
this.serialPort.BaudRate = 115200;
this.serialPort.WriteTimeout = 10 * 1000;
this.serialPort.ReadTimeout = 10 * 1000;
sequence = 0;
}

~SerialPortMgr()
{
if (serialPort.IsOpen)
{
ShutDownDevice();
}
}

private bool StartUpDevice(string portName)
{
try
{
if (!serialPort.IsOpen)
{
serialPort.Open();
string cmd = "FF007003AAAAAA26";//与机具握手
byte[] resp=null;
ExecRawCmd(cmd, ref resp, 0);
}
}
catch (Exception exc)
{
throw new Exception(string.Format("打开端口{0}失败!", portName));
}
return true;
}

private bool ShutDownDevice()
{
if (serialPort.IsOpen)
{
try
{
serialPort.Close();
}
catch (Exception)
{
throw new Exception(string.Format("关闭端口{0}失败!", serialPort.PortName));
}
}
return true;
}

private uint ExecCmd(string command, ref byte[] resp, int cardJack)
{

System.GC.Collect();

uint sw = uint.MinValue;
string comm = command.Replace(" ", "");
if (comm.Length < 4)
{
throw new Exception(string.Format("指令长度小于4,错误!指令:{0}", command));
}
if (!serialPort.IsOpen)
{
throw new Exception(string.Format("串口{0}未打开!", serialPort.PortName));
}
byte[] response = new byte[256];
byte[] sendBuffer =
SysHelper.CombineBytes(
new byte[] { 0xFF },
SysHelper.Int2Bytes(++sequence % 8, 1),
new byte[] { 0x60 },//pro卡命令
SysHelper.Int2Bytes(comm.Length / 2, 1),
SysHelper.HexString2Bytes(comm)
);
sendBuffer = SysHelper.Combine2Bytes(
sendBuffer,
new byte[] { SysHelper.GetXOR(sendBuffer) }
);

Log.Log.PutLog(string.Format("串口指令: {0}", SysHelper.Bytes2HexString(sendBuffer)));

int retryCount = 1;//由于无线接口,失败指令重试1次
int receiveCount = 0;
do
{
serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();
serialPort.Write(sendBuffer, 0, sendBuffer.Length);
System.Threading.Thread.Sleep(200);
receiveCount = serialPort.Read(response, 0, serialPort.BytesToRead);
if (receiveCount < 5 ||//长度错
response[0] != 0xFF ||//帧头错
response[1] != (byte)(sequence % 8) ||//序列号错
response[2] != 0x00 ||//指令执行失败
response[3] != receiveCount - 5 ||//数据长度错
// 异或校验错
response[receiveCount - 1] != SysHelper.GetXOR(SysHelper.SubBytes(response, 0, receiveCount - 1)))
{
if (retryCount-- > 0)
{
continue;
}
}

} while (retryCount-- > 0 && response[2] != 0x00);



Log.Log.PutLog(string.Format("串口返回: {0}", SysHelper.Bytes2HexString(
SysHelper.SubBytes(response,0,receiveCount))));


if (receiveCount < 5)//长度错
{
throw new Exception(string.Format("执行指令:{0},返回数据的长度错误!返回数据:{1}", command, SysHelper.Bytes2HexString(SysHelper.SubBytes(response, 0, receiveCount))));
}
if (response[0] != 0xFF)//帧头错
{
throw new Exception(string.Format("执行指令:{0},返回数据的帧头应该为FF!返回数据:{1}", command, SysHelper.Bytes2HexString(SysHelper.SubBytes(response, 0, receiveCount))));
}
if (response[1] != (byte)(sequence % 8))//序列号错
{
throw new Exception(string.Format("执行指令:{0},返回数据的序号!返回数据:{1}", command, SysHelper.Bytes2HexString(SysHelper.SubBytes(response, 0, receiveCount))));
}
if (response[2] != 0x00)//指令执行失败
{
throw new Exception(string.Format("执行指令:{0},返回数据的成功标志!=00,失败!返回数据:{1}", command, SysHelper.Bytes2HexString(SysHelper.SubBytes(response, 0, receiveCount))));
}
if (response[3] != receiveCount - 5)//数据长度错
{
throw new Exception(string.Format("执行指令:{0},返回数据的长度域!返回数据:{1}", command, SysHelper.Bytes2HexString(SysHelper.SubBytes(response, 0, receiveCount))));
}
// 异或校验错
if (response[receiveCount - 1] != SysHelper.GetXOR(SysHelper.SubBytes(response, 0, receiveCount - 1)))
{
throw new Exception(string.Format("执行指令:{0},返回数据的异或校验失败!返回数据:{1}", command, SysHelper.Bytes2HexString(SysHelper.SubBytes(response, 0, receiveCount))));
}

resp = SysHelper.SubBytes(response, 4, response[3] - 2);
sw = SysHelper.SubBytes(response, receiveCount - 3, 2)[0];
sw <<= 8;
sw += SysHelper.SubBytes(response, receiveCount - 3, 2)[1];

if (sw != 0x9000)
{
throw new Exception(string.Format("执行指令失败!\r\n指令:{0}\r\n错误码:{1:X}\r\n卡座:{2}\r\n接口设备类型:{3}", command, sw, cardJack, this.GetType().ToString()));
}
return sw;
}

#region IIFDMgr 接口的实现

bool IIFDMgr.isConnect()
{
return serialPort.IsOpen;
}

bool IIFDMgr.StartUpDevice(string port)
{
return StartUpDevice(port);
}

bool IIFDMgr.StartUpDevice()
{
return StartUpDevice(this.serialPort.PortName);
}

bool IIFDMgr.ShutDownDevice()
{
return ShutDownDevice();
}

uint IIFDMgr.ExecCmd(string command, ref byte[] resp, int cardJack)
{
return ExecCmd(command, ref resp, cardJack);
}

uint IIFDMgr.ExecCmd(string command, ref string resp, int cardJack)
{
uint ret = uint.MinValue;
byte[] bResp = null;
ret = ExecCmd(command, ref bResp, cardJack);
resp = SysUtilities.SysHelper.Bytes2HexString(bResp);
return ret;
}

#endregion
}
}
guoyichao 2009-10-23
  • 打赏
  • 举报
回复
应该不是gc崩溃,而是你的通讯组件出问题,你尝试下把你通讯组件内用到的对象都用GC.KeepAlive保持住
jizhiguo 2009-10-23
  • 打赏
  • 举报
回复
“后台为了定位问题”应改为“后来为了定位问题”
jizhiguo 2009-10-23
  • 打赏
  • 举报
回复
开始的时候,我没有在每条串口指令前调用GC.Collect(),而是由CLR负责垃圾回收,这样,程序崩溃就是不可预期的,有可能是几十条串口指令就崩溃,也可能几百条才崩溃。

后台为了定位问题,我才手动在每条串口指令前调用GC.Collect(),这样一来,崩溃就可准确重现了,一定是在执行完n条串口指令后,在执行n+1 条串口指令前调用GC.Collect()时崩溃。注:n是常数,且这n条指令每次执行都是一样的指令。第n+1条也是每次执行都是一样的指令。

高手帮我分析分析,已经好几天了,找不到解决办法。
jizhiguo 2009-10-23
  • 打赏
  • 举报
回复
hi,lerit,thx for your response.

我加入GC.Collect()的目的就是确认是GC引起的错误。我的代码在没有手动调用GC.Collect()的情况下,出现崩溃的时间不定(1分钟~10分钟不等),但一定会发生。后来加了GC.Collect()就能确定地重现问题了。具体重现的步骤如主贴所述。发生崩溃时,程序正在和串口通信。

lerit 2009-10-22
  • 打赏
  • 举报
回复
个人分析,你应该在强制回收时配合SuppressFinalize()方法来挂起线程。另外,应该说,垃圾回收本身只会清除不再使用的资源,因此不会因为这个回收了还在使用的资源而出错,主要是你现在强制垃圾回收时候,GC就会将所有线程挂起,那么这个挂起很有可能就是你总出错的原因,尤其是在于外部设备通信过程中,会导致实时的数据交换被中断,从而在你代码中出现错误。
鸭梨山大帝 2009-10-22
  • 打赏
  • 举报
回复
为什么要强制调用GC.Collect()来回收垃圾?
让其自己工作不好吗?
如果调用了非托管的东西,手动释放掉就是了,不必要GC强制回收,频繁的GC强制回收会导致不预期的错误的.
而且不好查

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧