CLR GC线程行为:SafeFileHandle意外完成

时间:2018-08-01 10:54:08

标签: c# .net garbage-collection safefilehandle

我们最近遇到了一些可能与CLR的GC行为有关的问题。

我遇到的问题如下:

我们有一个使用C#编写的长期运行的压力测试应用程序,该应用程序会继续打开远程SMB文件共享(即Azure文件服务)上的文件句柄,并使用这些句柄执行文件系统操作(例如读/写等)。< / p>

通常,我们会长时间打开这些手柄,因为我们会反复使用它们。但是有时候,当我们尝试访问其中一些打开的手柄时,我们发现这些手柄已经关闭。并从Process Monitor捕获的跟踪日志中(下面是一个示例):


fltmgr.sys!FltpPerformPreCallbacks + 0x324
fltmgr.sys!FltpPassThroughInternal + 0x8c
fltmgr.sys!FltpPassThrough + 0x169
fltmgr.sys!FltpDispatch + 0x9e
ntoskrnl.exeIopCloseFile + 0x146
ntoskrnl.exeObpDecrementHandleCount + 0x9a
ntoskrnl.exeNtClose + 0x3d9
ntoskrnl.exeKiSystemServiceCopyEnd + 0x13
ntdll.dll!ZwClose + 0xa
KERNELBASE.dll!CloseHandle + 0x17
mscorlib.ni.dll!mscorlib.ni.dll!+ 0x566038
clr.dll!CallDescrWorkerInternal + 0x83
clr.dll!CallDescrWorkerWithHandler + 0x4a
clr.dll!DispatchCallSimple + 0x60
clr.dll!SafeHandle :: RunReleaseMethod + 0x69
clr.dll!SafeHandle :: Release + 0x152
clr.dll!SafeHandle :: Dispose + 0x5a
clr.dll!SafeHandle :: DisposeNative + 0x9b
mscorlib.ni.dll!mscorlib.ni.dll!+ 0x48d9d1
mscorlib.ni.dll!mscorlib.ni.dll!+ 0x504b83
clr.dll!FastCallFinalizeWorker + 0x6
clr.dll!FastCallFinalize + 0x55
clr.dll!MethodTable :: CallFinalizer + 0xac
clr.dll!WKS :: CallFinalizer + 0x61
clr.dll!WKS :: DoOneFinalization + 0x92
clr.dll!WKS :: FinalizeAllObjects + 0x8f
clr.dll!WKS :: FinalizeAllObjects_Wrapper + 0x18
clr.dll!ManagedThreadBase_DispatchInner + 0x2d
clr.dll!ManagedThreadBase_DispatchMiddle + 0x6c
clr.dll!ManagedThreadBase_DispatchOuter + 0x75
clr.dll!ManagedThreadBase_DispatchInCorrectAD + 0x15
clr.dll!Thread :: DoADCallBack + 0xff
clr.dll!ManagedThreadBase_DispatchInner + 0x1d822c
clr.dll!WKS :: DoOneFinalization + 0x145
clr.dll!WKS :: FinalizeAllObjects + 0x8f
clr.dll!WKS :: GCHeap :: FinalizerThreadWorker + 0xa1
clr.dll!ManagedThreadBase_DispatchInner + 0x2d
clr.dll!ManagedThreadBase_DispatchMiddle + 0x6c
clr.dll!ManagedThreadBase_DispatchOuter + 0x75
clr.dll!WKS :: GCHeap :: FinalizerThreadStart + 0xd7
clr.dll!Thread :: intermediateThreadProc + 0x7d
KERNEL32.dll!BaseThreadInitThunk + 0x1a
ntdll.dll!RtlUserThreadStart + 0x1d

似乎在CLR GC Finalizer线程中关闭了句柄。但是,我们的句柄是按以下模式打开的,不应通过GC进行

我们使用P / Invoke打开文件句柄并获取SafeFileHandle,然后使用该SafeFileHandle构造FileStream,然后将FileStream对象保存在另一个定义如下的对象中:

public class ScteFileHandle
{
    /// <summary>
    /// local file handle
    /// </summary>
    [NonSerialized]
    public FileStream FileStreamHandle;

    /*
     * Some other fields
     */

}

我们使用的P /调用:

    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern SafeFileHandle CreateFile(
       string lpFileName,
       Win32FileAccess dwDesiredAccess,
       Win32FileShare dwShareMode,
       IntPtr lpSecurityAttributes,
       Win32FileMode dwCreationDisposition,
       Win32FileAttributes dwFlagsAndAttributes,
       IntPtr hTemplateFile); 

SafeFileHandle fileHandle = Win32FileIO.CreateFile(fullFilePath,win32FileAccess,win32FileShare,IntPtr.Zero,win32FileMode,win32FileAttr,IntPtr.Zero);

FileStream fileStream =新的FileStream(fileHandle,fileAccess,Constants.XSMBFileSectorSize);

我们可以确定的一件事是,在压力测试应用程序的整个生命周期中,我们肯定会保留对ScteFileHandle对象的引用,因此它永远不会被GC清除。但是,我们确实观察到ScteFileHandle的FileStream中引用的SafeHandle已在CLR GC线程中完成,如上面的跟踪日志中所述。

所以我想知道是什么原因导致SafeFileHandle被GC填充,是否有任何方法可以避免这种情况?我不熟悉CLR GC的行为,但从我的角度来看,不应将SafeFileHandle进行GC。

任何指针或见识都将不胜感激!请让我知道您是否需要诊断此问题的其他详细信息:)

0 个答案:

没有答案