使用.net SerialPort出现内存泄漏,有更好的方法吗?

发布于 2024-10-04 01:05:43 字数 394 浏览 0 评论 0原文

我有一个程序用于通过 rs232 与硬件通信。该软件用于显示从硬件通过 rs232 尽可能快地推送的数据流。我遇到的问题是,随着时间的推移,分配给程序的私有内存会爆炸,并且会很快使程序崩溃。如果我禁用硬件发送数据大约 2 分钟,那么软件可以清除内存,但前提是我暂停数据流。

我正在使用来自 SerialPort 的 DataReceived 事件,这似乎就是问题所在,因为即使 DataReceived 函数在其中不执行任何操作,它也会导致内存峰值。 时没有时间运行 GC。

我唯一能想到的是,每次引发此事件时,它都会创建一个新线程来运行,并且它发生的速度如此之快,以至于计算机在数据传入 从 SerialPort 对象中提取数据的更有效方法?当我收到“NewLine”时我只关心字符串?

谢谢,

约翰·维克斯

I have a program that is used to talk to hardware over rs232. This software is used to display a stream of data that is pushed over the rs232 from the hardware as fast as it can be. The problem I am running into is that over time the private memory assigned to the program explodes, and will very rapidly crash the program. If I disable the hardware from sending data for about 2 minutes, then the software can clear out the memory, but only if I pause the data stream.

I am using the DataReceived event from the SerialPort, and this appears to be where the problem is at, because it will cause a memory spike even if the DataReceived function does nothing inside it. The only thing I can come up with is that every time this event is raised it creates a new thread to run, and it is happening so fast that the computer doesn't have time to run GC while the data is coming in.

Is there a more efficient way to pull data off a SerialPort object? I only care about a string when I receive a "NewLine"?

Thanks,

John Vickers

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

剑心龙吟 2024-10-11 01:05:44

非常不寻常,但在技术上是可行的。 SerialPort 使用线程池线程来调用 DataReceived 事件处理程序。一旦它收到一个或多个字节,它就会获取一个 TP 线程来通知您的应用程序。事件生成代码中有一把锁,一次只有一个线程可以调用您的事件处理程序。

这里潜在的失败模式是这些调用之一(可能是第一个调用)进入代码中的循环,并且永远不会退出。如果您尚未设置握手属性,设备可以继续发送并触发更多 TP 调用,所有这些调用都会在该锁上阻塞。

从“调试”+“Windows”+“线程”窗口诊断此问题。如果我的猜测是准确的,那么您应该会看到这里列出了大量的线程。其中之一应该位于您的 DataReceived 事件处理程序中,双击它并查看调用堆栈以查看它被卡住的位置。您看到消耗的内存被这些线程的堆栈占用,每个线程一兆字节。

另一种可能性是您的 DataReceived 事件处理代码非常很慢,可能是通过调用 Control.Invoke() 实现的。速度太慢,无法跟上设备。您现在确实需要使用握手属性来设置流量控制。或者修复任何让它变慢的东西。顺便说一句,还应该有大量的 ErrorReceived 事件,请务必实现它,以便您可以看到这些东西出了问题。

可同时运行的 TP 线程数有上限。它相当慷慨,是核心数量的 250 倍。在典型的双核机器上,这很容易消耗半千兆字节的内存。

This is very unusual but it is technically possible. SerialPort uses threadpool threads to call the DataReceived event handler. As soon as it receives one or more bytes, it grabs a TP thread to notify your app. There's a lock in the event generation code, only one thread can call your event handler at a time.

A potential failure mode here is that one of these calls, likely the first one, enters a loop in your code from which it never exits. If you haven't set up the Handshake property, the device can keep sending and triggering more TP calls, all of them blocking on that lock.

Diagnose this from the Debug + Windows + Threads window. If my guess is accurate then you should see a large number of threads listed here. One of them should be inside your DataReceived event handler, double-click it and look at the call stack to see where it is stuck. The memory you are seeing consumed is eaten by the stacks of these threads, one megabyte each.

Another possibility is that your DataReceived event handling code is very slow, possibly by calling Control.Invoke(). Slow enough to not be able to keep up with the device. You now really do need to use the Handshake property to setup flow control. Or fix whatever makes it so slow. There should also be a very large number of ErrorReceived events btw, be sure to implement it so you can see this stuff going wrong.

There's an upper limit on the number of TP threads that can be running at the same time. It is rather generous, 250 times the number of cores. That can easily consume half a gigabyte of memory on a typical dual-core machine.

时光是把杀猪刀 2024-10-11 01:05:44

DataReceived 在不同的线程上执行。我在处理非常快的数据时遇到了问题,这个事件给我带来了问题。因此,我创建了一个线程并自己读取数据:

while (this.serialPort.IsOpen)
{
    int b = this.serialPort.ReadByte();
    if (b != -1)
    {
        // data is good here
    }
}

但正如其他人所说,没有任何代码示例,我们无法为您提供太多帮助。

DataReceived is executed on a different thread. I had problems with really fast data and this event caused me problems. Because of that, I created one thread and read the data myself:

while (this.serialPort.IsOpen)
{
    int b = this.serialPort.ReadByte();
    if (b != -1)
    {
        // data is good here
    }
}

But like the others said, without any code sample, there isn't much we can help you with.

染年凉城似染瑾 2024-10-11 01:05:44

只是为了重温这个问题。

使用 DataReceived 事件时,我发现存在大量内存泄漏。

我使用的是 USB 3G 调制解调器,它提供串行调制解调器接口。我编写了一个小程序,它只打开串行端口并连接到 DataReceived 事件。事件处理程序只是一个空方法。

如果您拔出加密狗,内存就会以每秒约 10MB 的速度泄漏。没有抛出异常。

启动一个新线程并使用同步 Read(...) 方法为我解决了这个问题。现在,当我拔出我可以处理的加密狗并且没有内存泄漏时,我遇到了异常。

Just to revive this issue.

I'm seeing a massive memory leak when using the DataReceived event.

I am using a USB 3G modem which provides a serial modem interface. I wrote a tiny program that just opens the serial port and connects to the DataReceived event. The event handler is just an empty method.

If you yank out the dongle memory starts to leak at about 10MB per second. No exception is thrown.

Spinning up a new thread and using the synchronous Read(...) method solved the problem for me. I now get an exception when I yank out the dongle that I can handle and no memory leaks.

铜锣湾横着走 2024-10-11 01:05:44

我用 C# 开发了一种状态驱动的串行端口编程语言,我相信它确实解决了几乎每个人遇到的所有串行端口问题。

请您尝试使用以下简单状态并检查内存泄漏吗?

state Init
  recv();
  $len = length($DATA_PACKET);
  if("$len > 0") {
    log($DATA_PACKET, Debug);
  }
end state

屏幕截图

项目主页

下载

如果您有任何疑问,请随时提问。

I developed a state-driven serial port programming language in C# and I believe it really solves nearly all of the serial port problems that everybody encounters with.

Would you please try it with the following simple state and check memory leaks ?

state Init
  recv();
  $len = length($DATA_PACKET);
  if("$len > 0") {
    log($DATA_PACKET, Debug);
  }
end state

Screen shots

Project homepage

Download

If you have any questions, please feel free to ask.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文