【问题标题】:How do I know if my serial comms are being closed by GC?我如何知道我的串行通讯是否被 GC 关闭?
【发布时间】:2020-05-31 12:12:13
【问题描述】:

我有一个SerialPort 对象。我已经为此放置了一个事件处理程序来监控处置、异常和接收到的数据事件:

mySp.DataReceived += sp_DataReceived;
mySp.ErrorReceived += sp_ErrorReceived;
mySp.Disposed += sp_Disposed;

几分钟后我停止接收数据,但我有充分的理由相信这不是串行消息发送者的问题。

我之前在这个应用程序中遇到过问题,因为 GC 处理了我需要的东西(Threading.Timer 对象),所以我想确保这个 SerialPort 没有被处理。我附加了一个 Disposed 处理程序,但我刚刚读到 GC 不会调用 Dispose - 那么我如何判断它是 GC 还是其他地方的问题?

【问题讨论】:

  • 订阅事件不会使对象保持活动状态,所以是的,如果您不在某处保留对它的引用,它将被 GC 收集。我会找到一个正确答案的链接。编辑:this 有帮助吗?
  • 导致问题的不是 GC。可能不会在一个块上接收到消息。使用异步串行端口时,Windows 中使用时间来发送接收数据。因此,您的代码必须能够等到收到完整的消息。您有一个主/从通信系统。您的代码是主机(客户端),设备是从机(服务器)。除非服务器收到消息并发送响应,否则您不会收到消息。您的代码挂起,但绝对不是因为垃圾收集。
  • 如果串行端口超出范围,它们应该被丢弃。只是问这个问题表明你没有这样做。开放端口是非托管资源。对于那些规则是:“创建。使用。处置。所有在同一段代码中,理想情况下使用 using 块。” docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
  • @Christopher - 不过,我需要让这些通讯“永远”保持打开状态。我没有自己处理它们的奢侈,因为我不想错过任何一条消息,这是作为 Windows 服务的一部分,它可以不间断地运行。基本上,这是一种监视串行端口的消息并立即显示它们的服务。

标签: c# .net garbage-collection serial-port dispose


【解决方案1】:

对于 GC,我们永远不能说它是否被收集或何时被收集 - 只有当它可以被收集时。规则是“GC 可以收集没有对应用程序根的强引用链的所有内容”。如果你知道了,GC 就不会碰它。如果你没有它,GC 可能最终会碰它。

运行 GC 的成本很高。在它收集时,所有其他线程必须暂停。因此,框架在运行它时很懒惰。如果它只运行一次——在应用程序关闭时——那是理想的情况。在此之前,只有一些罕见的场景才能将其付诸实践:

  • OOM 异常的危险。在这些发生之前,GC 将收集它所能收集到的所有东西。
  • 手动调用
  • 各种优化。就像试图收集您在刚刚完成的函数中创建的所有内容一样。
  • 任何备用 GC 策略,例如针对服务器优化的策略

至于你的问题:

只要对某事保持强引用,就无法收集

如果你有一个强引用,GC 必须假设你正在处理它并且它不应该删除它。它可能仍然会用它做其他背景工作(比如在内存中移动它),但这些更改通常对你来说是不可见的。

像这样的 GC 导致内存泄漏的唯一方法是忘记删除对某事物的所有强引用。大多数情况下,人们忘记将其从集合中删除。

根据设计,事件处理程序不能算作“完整的强引用链”。 GUI Automatics 已经对显示的所有内容(以及仅隐藏而非未显示的内容)拥有强大的引用链。

我认为你正在做一些奇怪的多任务处理方式:

  • 你创建一个实例
  • 您注册活动
  • 你没有保留一个强有力的参考

这行不通。您需要使用适当的多任务处理方式 - 理想情况下使用一些阻塞或轮询代码 - 来处理它们。这也将允许您从 SerialPorts 中获取异常。

【讨论】:

    【解决方案2】:

    要回答“我如何知道我的对象是否被收集”的问题:

    1. 检查代码。确保您保留对相关对象的引用。
    2. 您可以包装对象并将finalizer 添加到包装器中。如果您到达终结器,您就知道您的对象即将被收集。
    3. 使用内存分析器。这使您可以捕获快照并搜索内存中的对象数量。这样您就可以查看您使用的任何对象是否存在。我不知道有任何合适的免费替代品,但通常有商业系统的试用版。

    其他注意事项:

    1. 确保您注意发生的任何异常和其他故障。某些 API 具有事件或其他扩展点,您可以在其中侦听问题。这可能会揭示是否存在导致消息停止的内部问题。
    2. 不确定您使用什么进行串行通信,但某些库甚至驱动程序可能不可靠。切换版本甚至硬件以查看是否可以避免问题可能是一个想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-03
      • 2011-10-21
      • 2021-12-16
      • 2021-07-09
      • 2012-03-07
      • 1970-01-01
      • 1970-01-01
      • 2011-09-05
      相关资源
      最近更新 更多