【问题标题】:fatal error in gc collecting from unknown thread从未知线程收集 gc 时出现致命错误
【发布时间】:2020-02-10 11:58:56
【问题描述】:

我正在使用 Microsoft-IIS/10.0、AspNetMvc-Version: 5.2、AspNet-Version: 4.0.30319 来运行我的应用程序。当我从非托管 dll(C 代码)调用函数时,问题发生了。一切运行良好,可运行 3 次或最多 5 次。之后发生“致命错误”并且应用程序停止。任何帮助都会受到欢迎。谢谢和问候

【问题讨论】:

    标签: asp.net asp.net-mvc garbage-collection


    【解决方案1】:

    如果使用非托管资源,您必须释放它们,或者如果已经释放,则不要尝试再次释放它们。一些代码在这里会有很大帮助,但听起来你在 finalize 方法中碰到了一个空指针或其他东西,然后垃圾收集器试图处理带有被引用的空指针的对象。

    例如

    [DllImport("user32.dll")]
    static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
    [DllImport("user32.dll", SetLastError=true)]
    static extern IntPtr GetDC(IntPtr hWnd);
    public class ExampleClass
    {
       private int _hwnd;
       private IntPtr _dc;   
       public ExampleClass(int hwnd) : IDispose
       {
          this._dc = GetDC(hWnd);
          this._hwnd = hwnd;
          Console.WriteLine("Got pointer to device context of window with hWnd" + hwnd.toString());
       } 
    
       public void Dispose(){
          ReleaseDc(this._hwnd, this._ds);
       }
    
       ~ExampleClass()
       {
          Console.WriteLine("Finalizing object");
          ReleaseDc(this._hwnd, this._ds); //Bang, the handle was already released in the dispose method....
       }
    }
    

    【讨论】:

    • 感谢您的回复。我正在对非托管资源使用“using (...)”命令。
    • 确实是。然而,这并不意味着这就是故事的结局。参见上面的代码,如果你使用 using(...) 命令,这意味着 Dispose 方法会被自动调用。就是这样。这就是它所做的一切。现在,如果 Dispose 方法释放了指针引用的内存,然后您尝试在 finalize 方法中重新释放它,该方法由 GC 在将来的任何时候调用,那么 booooooooom....
    • 非常感谢您的意见。我想我发现了错误。我正在调用内核 dll 的免费方法而不是非托管资源。再次感谢
    【解决方案2】:
    Here is my code:
    
    public class FmuInstance : IDisposable
    {
        private readonly string fileName;
        private IntPtr wrapper;
    
        [DllImport("kernel32.dll")]
        public static extern IntPtr LoadLibrary(string lpFileName);
    
        [DllImport("kernel32.dll")]
        public static extern IntPtr FreeLibrary(IntPtr library);
    
    
        public void LoadDLL(string path)
        {
            wrapper = LoadLibrary(path);
            if (wrapper == IntPtr.Zero)
                throw new DllNotFoundException("----");
            FreeLibrary(wrapper);
        }
    
        public void FreeDLL()
        {
            FreeLibrary(wrapper);
        }
    
        public void FreeInstance()
        {
            if (wrapper != IntPtr.Zero)
                FreeDLL();
            wrapper = IntPtr.Zero;
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // Free managed resources
                }
                // Free unmanaged resources
                FreeInstance();
                // Avoid disposing multiple times
                disposedValue = true;
            }
        }
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
    

    【讨论】:

    • 这里有我的非托管资源。还是行不通。我不知道我做错了什么。
    • 您的 if 语句将永远不会在 Dispose 方法中触发,因为从未设置过disposedValue,而且不会在方法范围之外(即在类级别)声明更多内容。实际上,您的 FreeInstance() 方法永远不会被调用。把调试语句放进去看看! :-)
    猜你喜欢
    • 2022-11-10
    • 2011-07-13
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多