繁体   English   中英

为什么在作为参数传递时收集了委托函数引用垃圾?

[英]Why is a delegate function reference garbage collected when passed as parameter?

我正在使用鼠标和键盘窗口挂钩编写C#空闲监视器

public class KeyboardHook : WindowsHook
{
    private static event KeyEventHandler _KeyDown = null;

    public static void Hook(KeyEventHandler onKeyDown)
    {
        _KeyDown = onKeyDown;

        SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback); // PROBLEM!!
    }

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && wParam == (IntPtr)KeyboardMessage.WM_KEYDOWN)
        {
            int vkCode = Marshal.ReadInt32(lParam);
            _KeyDown(null, new KeyEventArgs((Keys)vkCode));
        }
        return CallNextHookEx(nCode, wParam, lParam);
    }
}

在上面的代码中,HookCallback被传递到SetWindowsHookEx。 代码编译并正常运行,但在稍后的某个时间,HookCallback会收集垃圾,Visual Studio调试器会捕获它。

在下面的代码中,HookCallback是使用_HookProc间接分配的,到目前为止它似乎运行正常。 我可以看到为什么下面的代码有效,但我不确定为什么直接分配(如上所述),HookCallback没有引用(“存储”)某个地方不会导致它被GC编辑?

public class KeyboardHook : WindowsHook
{
    private static HOOKPROC _HookProc = HookCallback; // saving a reference locally

    private static event KeyEventHandler _KeyDown = null;

    public static void Hook(KeyEventHandler onKeyDown)
    {
        _KeyDown = onKeyDown;

        SetWindowsHookEx(WH_KEYBOARD_LL, _HookProc);
    }

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        // ...
    }
}

请记住,一般情况下,系统不知道您将要调用哪些本机函数。 对于大多数情况,只要在函数调用正在进行时(仅可能)使用传入本机函数的函数指针,.NET系统已经足够确保可以调用该函数。

但是在你的情况下,你正在传递一个函数指针,它将在其他时间点被调用,就在SetWindowsHookEx返回之后。 在这种情况下, 您有责任确保代表保持足够长的生命。

而且,从外观上看,你已经找到了实现这一目标的方法。


替代方案是:a)传递给任何本机函数的任何委托都不会被垃圾收集,从而产生可能的内存泄漏,或者b)系统必须为您的代码提供一种机制,以指示它何时知道不再需要该委托。 但是这样的机制仍然需要您的代码的合作,而不仅仅是让您管理托管对象的生命周期。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM