0

I have a SerialPort object. I have put an event handler on this to monitor disposal, exceptions and received data events:

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

After a few minutes I stop receiving data, but I have good reason to believe this is not an issue with the sender of the serial messages.

I've had issues in this app before with GC disposing things I needed (Threading.Timer objects), so I want to make sure this SerialPort is not being disposed. I attached a Disposed handler, but I've just read GC would not invoke Dispose - so how can I tell if it's GC or an issue elsewhere?

JᴀʏMᴇᴇ
  • 218
  • 2
  • 15
  • 1
    Subscribing to events doesn't keep objects alive, so yes it will be collected by GC if you don't keep a reference to it somewhere. I'll find a link to a proper answer. EDIT: does [this](https://stackoverflow.com/questions/298261/do-event-handlers-stop-garbage-collection-from-occurring) help? – Corentin Pane May 31 '20 at 12:29
  • It is not the GC that is causing the issue. Messages may not be received on one chunk. When using Async serial port times are used in windows to send receive data. So your code has to be able to wait until an entire message is received. You have a Master/Slave communication system. Your code is the master (client) and the device is the slave (server). You will not receive a message unless the server gets the message and sends a response. You code is hanging but absolutely not due to garbage collection. – jdweng May 31 '20 at 12:40
  • If the Serial Ports run out of scope, they **should be disposed off**. Just asking the question indicates you did not do that. A open Port is a unmanaged Resource. For those the rule is: "Create. Use. Dispose. All in the same piece of code, ideally using a using block." https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement – Christopher May 31 '20 at 13:13
  • @Christopher - I need to keep these comms open 'forever', though. I don't have the luxury of disposing them myself since I don't want to miss a single message and this is as part of a windows service that is to run without stopping. Basically, a service that watches a serial port for messages and displays them instantly. – JᴀʏMᴇᴇ May 31 '20 at 13:36

2 Answers2

1

With the GC we can never say if it is or when it is collected - only if it CAN be collected. The rule is "the GC can collect everything that does not have a chain of strong references to a application root." If you got that, the GC will not touch it. If you do not have it the GC may touch it - eventually.

Running the GC is expensive. While it collects, all other threads must pause. Accordingly the Framework is lazy at running it. If it only runs once - on application closure - that is the ideal case. Before that only some rare scenarios can get it into action:

  • The danger of a OOM Exception. Before those happen, the GC will have collected everything it can.
  • Manually calling it
  • various optimsiations. Like trying to collect everything you created inside the function you just finished.
  • any alternate GC strategy, like the one optimized for servers

As for your problem:

As long as you keep a strong reference to something, it can not be collected.

If you got a strong reference, the GC has to assume you are working on it and it is not supposed to remove it. It may still do other background stuff with it (like moving it around in memory), but those changes are usually invisible for you.

The only way to cause a memory leak with a GC like this, is to forgetting to remove all strong references to something. Mostly it is people forgetting to remove it from a Collection.

Event handlers by design do not count as "a unbroken chain of strong references". GUI Automatics already have a strong reference chain to everything that is displayed (and the stuff that is only hidden, not undisplayed).

I think you are doing some wierd way of multitasking like this:

  • you create a instance
  • you register events
  • you do not keep a strong reference

This will not work. You need to use a proper way of multitasking - ideally using some blocking or polling code - to process them. That would also allow you to get Exceptions out of the SerialPorts.

Christopher
  • 9,634
  • 2
  • 17
  • 31
0

To answer the question "how do I know if my objects are collected":

  1. Inspect the code. Ensure that you keep a reference to the object in question.
  2. You can wrap the object and add a finalizer to the wrapper. If you reach the finalizer you know your object is about to be collected.
  3. Use a memory profiler. This lets you capture a snapshot and search for the number of objects in memory. That way you can see if whatever object you use exists or not. I'm not aware of any competent free alternative, but there are often trial versions of the commercial systems.

Other things to keep in mind:

  1. Ensure you watch for any exceptions and other faults that occur. Some APIs have events or other extension points where you can listen for problems. This might reveal if there is some internal problem causing the messages to stop.
  2. Not sure what you are using for serial communication, but some libraries or even drivers can be unreliable. It might be an idea to switch versions or even hardware to see if this avoids the problem.
JonasH
  • 28,608
  • 2
  • 10
  • 23