- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在使用 USB 设备。此设备接收消息,但我不知道何时或多久接收一次。驱动程序附带的 API 指定了一个 setreceiveCallBack 函数,该函数在设备收到消息时提供回调。但是在随机的时间或间隔,我会收到有关垃圾收集委托(delegate)异常的回调。我已经为我的问题寻找解决方案,但似乎没有一个解决方案适用于我的情况。以下是我的代码的最大部分:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace CallBacktesting
{
public unsafe delegate void callBack(Form1.CANMsg *pmsg);
public partial class Form1 : Form
{
uint handle;
static WriteLog log = new WriteLog();
Boolean getCan = false;
static int frameCount = 0;
static CANMsg newmsg = new CANMsg();
callBack _setCallBack;
List<string> write = new List<string>();
public Form1()
{
InitializeComponent();
}
private void buttonOpen_Click(object sender, EventArgs e)
{
// Open connection
}
private void buttonClose_Click(object sender, EventArgs e)
{
// Close connection
}
private void buttonCallBack_Click(object sender, EventArgs e)
{
if (!getCan)
{
int rv;
unsafe
{
callBack _setCallBack = new callBack(call);
rv = canusb_setReceiveCallBack(handle, _setCallBack);
}
label1.Text = rv.ToString();
}
else
{
_setCallBack = null;
int rv = canusb_setReceiveCallBack(handle, _setCallBack);
GC.KeepAlive(_setCallBack);
label1.Text = rv.ToString();
}
}
public unsafe void call(CANMsg *pmsg)
{
newmsg = *pmsg;
update();
}
private void buttonExit_Click(object sender, EventArgs e)
{
GC.KeepAlive(_setCallBack);
Application.Exit();
}
[DllImport("canusbdrv.dll", EntryPoint = "canusb_setReceiveCallBack")]
public static extern int canusb_setReceiveCallBack(uint handle, callBack callBack);
unsafe private void timer_Tick(object sender, EventArgs e)
{
// update the form with received messages
}
public void update()
{
CANMsg msgrec = newmsg;
// Build str from messages with all data
write.Add(str);
log.logWrite(str);
frameCount++;
}
}
public class WriteLog
{
private void OpenFile()
{ }
public void logWrite(string log)
{ }
public void logAdd(string log)
{ }
private void logClose()
{ }
}
}
最佳答案
在你的代码中,当你这样做的时候
callBack setCallBack = new callBack(call);
rv = canusb_setReceiveCallBack(handle, call);
在您调用“canusb_setReceiveCallBack”后,委托(delegate)将可用于垃圾回收,因为您的代码中没有任何地方引用委托(delegate)。
您可以避免将其存储在私有(private)字段中。
例如:
Class Form1
{
callBack _setCallBack;
private void buttonCallBack_Click(object sender, EventArgs e)
{
_setCallBack = new callBack(call);
rv = canusb_setReceiveCallBack(handle, _setCallBack);
}
}
但这可能会有一些问题,因为每次点击按钮都会创建一个新的回调。如果需要引用之前的回调,这可能会有问题。
我认为你应该做的是重构代码以使用 SafeHandle存储 canusb_Open 返回的句柄。
我会这样设计类(class)。
class CanUsbSafeHandle : SafeHandle
{
private EventHandler _receiveCallBack;
private readonly object _receiveCallBackLock = new object();
public event EventHandler ReceiveCallBack
{
add
{
lock (_receiveCallBackLock)
{
bool hasListeners = (_receiveCallBack != null);
_receiveCallBack += value;
//call canusb_setReceiveCallBack only when 1 or more listeners were added
//and there were previously no listeners
if (!hasListeners && (_receiveCallBack != null))
{
canusb_setReceiveCallBack(this, setCallBack);
}
}
}
remove
{
lock (_receiveCallBackLock)
{
bool hasListeners = (_receiveCallBack != null);
_receiveCallBack -= value;
//call canusb_setReceiveCallBack only when there are no more listeners.
if(hasListeners && (_receiveCallBack == null))
{
canusb_setReceiveCallBack(this, null);
}
}
}
}
public CanUsbSafeHandle()
: base(IntPtr.Zero, true)
{
}
public override bool IsInvalid
{
get { return handle == IntPtr.Zero; }
}
protected override bool ReleaseHandle()
{
return canusb_Close(handle);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
lock (_receiveCallBackLock)
{
_receiveCallBack = null;
}
}
base.Dispose(disposing);
}
}
这样,SafeHandle 将管理“接收回调”委托(delegate)的生命周期将由 SafeHandle 管理。
关于c# - CallBack on garbagecollected Delegate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1819638/
我正在尝试释放 C* 中的一些磁盘空间。 我已经删除了很多创建了很多墓碑的行。 我正在运行 nodetool garbagecollect 并且想知道这个工具在幕后做了什么。我读过它删除了逻辑删除正在
我正在尝试释放 C* 中的一些磁盘空间。 我已经删除了很多创建了很多墓碑的行。 我正在运行 nodetool garbagecollect 并且想知道这个工具在幕后做了什么。我读过它删除了逻辑删除正在
我正在使用 USB 设备。此设备接收消息,但我不知道何时或多久接收一次。驱动程序附带的 API 指定了一个 setreceiveCallBack 函数,该函数在设备收到消息时提供回调。但是在随机的时间
情况 我们正在运行一个大型 WPF 应用程序,该应用程序在相当长的一段时间内不会释放内存。这不是真正的内存泄漏,因为内存最终会被释放。我知道通常情况下,这不会被视为问题。不幸的是,它与 WPF 命令基
我是一名优秀的程序员,十分优秀!