C# - Trying to find remaining EventHandler prevent

2019-06-24 10:54发布

Long story short, I inherited a fairly complex application and I'm trying to track down a memory leak involving a form. Right now, every time the form is closed and a new one brought up, the old one remains in memory. I tracked down an issue with a static event owned and set by a control within the program (apparently, so long as the static event was set, no instance of that control was considered out of scope, even when no one else referred to said controls). Now, I'm trying to track down the remaining issue.

Using MemProfiler and ANTS Memory Profile, I've learned that the root execution path goes like this:

FormOpenWatch        <--       The item which remains active
System.EventHandler -- (this as Delegate)._target
System.Object[]
System.EventHandler -- (this as MultiCastDelegate)._invocationList
System.ComponentModel.EventHandlerList+ListEntry  --  handler
System.ComponentModel.EventHandlerList+ListEntry  --  next
System.ComponentModel.EventHandlerList+ListEntry  --  next
System.ComponentModel.EventHandlerList+ListEntry  --  next
System.ComponentModel.EventHandlerList+ListEntry  --  next
System.ComponentModel.EventHandlerList  --  head
PTU.MdiPTU  --  (this as Component).events        <--       The base application

Anyone have any insight for what I might be looking for? I've found a Shown event added with the base application, and ensured that it gets removed when the form is being disposed of, but that doesn't seem to have fixed the problem.

Much thanks for any help you can provide.

Later Edit: I have thought I've successfully solved this several times over now, and I'm still having issues. The problem seems to be stemming from my Plotter class (and various derived classes) having this "public static event MouseEventHandler MultiCursorMouseMove;" event. We have a "cursor" which displays the value and time of the graph at the mouse's location. Originally, this worked on one graph at a time, but a request was made to allow the user to toggle a mode where moving the mouse moved the plot across all of the displayed graphs. I wrote up an initial treatment hooking the EventHandlers in as the items were instantiated, and my partner across the pond rewrote it to use the static event, which gets assigned to each item on construction. His way is much more elegant and works better. All except that it's resulted in memory leaks. Using the memory profiling software has shown that every time I try to get rid of the form holding the plots, I'm left with a number of cases of "Disposed instance with direct EventHandler roots". In each of these, it shows that the object is either a Plotter, or an object pointed to by the Plotter. And, in each of these, the base link is that a MultiCursorMouseMove EventList points to these objects. I think that what's happening is that the Plotter is staying alive because it has this static event which in turn is linked to the Plotters. I have managed to verify that MultiCursorMouseMove is null through the debugger at a given point by virtue of my Dispose code removing the event for each Plotter, and yet running the profiler at that same point still shows this chain from MultiCursorMouseMove to these classes.

I'm out of ideas on how to fix this currently. Anyone?

1条回答
Evening l夕情丶
2楼-- · 2019-06-24 11:46

If MdiPTU is the MDI parent form for your application, it sounds like FormOpenWatch might have subscribed to one of its events. If it hasn't done so directly, you might find the subscription in a FormOpenWatch superclass, or perhaps even in other code that can wire up execution of a FormOpenWatch method from an MdiPTU event.

查看更多
登录 后发表回答