Memory leak with C# and flex form application - c#

I am experiencing Flex form black out issue in my project [Desktop App C# & Flex Forms] after opening multiple child windows with flex forms. While investigating this issue using memory profilier I found this is happening due to memory leaks. While closing child windows memory is not getting released completely even after waiting for few mins.
To narrow down the issue I have created a very simple light weight desktop app which launches child winform with blank Flex from the parent form button click. While closing child window I am properly disposing objects (axshockwaveFlashPlayer and proxy) and handles then also I see the memory keeps increasing for each child window and remain constant even after closing all the child windows. I have also tried to dispose objects at flex end while closing child window but no luck.
As per the DebugDiag profiler analysis report, \Flash32_22_0_0_209.ocx is responsible for 138.44 Mbytes with 95% leak probability.
However, I don’t find any option to release memory while closing a child form.
Can anyone suggest what else can be done to resolve this issue.
I am using Flash player version 22.0.0.209. Appreciate your help here.
As per VMMAP Tool memory analysis
If i open 10 child windows memory increase from 400 to 700MB and when i close all the child windows it comes down to only 600 MB and it reamins constant.
Please note committed memory always comes down to where it started.
Only concern is with "Private Data" which never comes down. I am not sure what is Private Data and what we can do from code to release that memory.
Please find below code for your reference
//Child form code start
public Childwindow1(string flexURLPath)
{
InitializeComponent();
this.Closing += Childwindow1_Closing;
host = new WindowsFormsHost();
player = new FlashAxControl();
_flexURL = flexURLPath;
host.Child = player;
this.grdChildWindow1.Children.Add(host);
player.LoadMovie(_flexURL); //call load movie method of user control to load
}
//While closing disposing objects
void Childwindow1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
host.Dispose();
player.Dispose();
host = null;
player = null;
}
//child form code ends here
//User Control code
//User Control - LoadMovie Method
public void LoadMovie(string strPath)
{
axShockwaveFlash.LoadMovie(0, strPath);
}
//user control - Disposing object - AXshockwave and calling GC
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
components = null;
}
if(disposing && (axShockwaveFlash != null))
{
Proxy.ExternalInterfaceCall -= ProxyExternalInterfaceCall;
Proxy.Dispose();
Proxy = null;
axShockwaveFlash.Dispose();
axShockwaveFlash = null;
}
base.Dispose(disposing);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}

Related

UnmanagedMemory leak when disposing a WindowsFormsHost

We are currently reworking a WindowsForms application in WPF.
The software is quite large and it will take years to finish it, so we have a hybrid system that displays pure WPF for the new panels and Hosted WindowsForms elements in WindowsFormsHosts controls.
We use Syncfusion's WPF Docking Manager to show these pages in tabs (not sure that this info is relevant).
We spent quite a lot of time to track down memory leaks (using JetBrains' DotMemory), but we run out of memory after opening and closing nearly 100 pages containing WindowsFormsHosts.
This memory leak is quite strange, as you can see in the memory profiling, it seems that the problem lies in the unmanaged memory.
DotMemory profiling
The WindowsFormsHosts seem to be correctly disposed as well as the Child content.
As suggested here WPF WindowsFormsHost memory leak, we wrap the WindowsFormsHosts in a grid that we clear when we want to dispose it:
public override void Dispose()
{
if (this.Content is Grid grid && grid.Children.Count == 1)
{
if (grid.Children[0] is KWFHost wfh)
{
wfh.Child.SizeChanged -= ControlSizeChanged;
wfh.Dispose();
}
grid.Children.Clear();
}
base.Dispose();
}
and
public class KWFHost : WindowsFormsHost
{
protected override void Dispose(bool disposing)
{
if (this.Child is IDisposable disposable)
{
disposable.Dispose();
}
this.Child = null;
base.Dispose(true);
}
}
We suspect that the Hosting causes the leak because in DotMemory, in memory allocation we can see this:
memory allocation
Is there any known issue with the WindowsFormsHosts that could explain this? Or a way for us to isolate the source of the problem?
Edit : Here is the code that adds the Grid and WindowsFormHost :
public void SetContent(System.Windows.Forms.Control control)
{
var host = new KWFHost();
host.Child = control;
control.SizeChanged += ControlSizeChanged;
var grid = new Grid();
grid.Children.Add(host);
this.Content = grid;
}
I finally figured it out:
After a bit more digging, I found out that the WindowsFormsHosts are kept alive.
DotMemory gives me two reasons for that.
the first one: System.Windows.Interop.HwndSourceKeyboardInputSite. For a reason that I can't explain, there is still a reference to the WindowsFormsHost in the ChildKeyboardInputSinks in the HwndSource. If someone knows why, I'd be interested in hearing the reason.
I don't know if there is a better way to get rid of this reference, but here's the code I wrote:
private void CleanHwnd(KWFHost wfh) //my implementation of WindowsFormsHost
{
HwndSource hwndSource = PresentationSource.FromVisual(wfh) as HwndSource;
//here I isolate the right element to remove based on the information I have
IKeyboardInputSink elementToRemove = hwndSource.ChildKeyboardInputSinks.FirstOrDefault(c => c is KWFHost h && h.Parent is Grid g && g.Parent is KWindowsFormsHost fh && Equals(fh.TabName, TabName));
//The method CriticalUnregisterKeyboardInputSink takes care of removing the reference but as it's protected I use reflection to get it.
var mi = typeof(HwndSource).GetMethod("CriticalUnregisterKeyboardInputSink",
BindingFlags.NonPublic | BindingFlags.Instance);
//here I remove the reference
mi.Invoke(hwndSource, new object[] { elementToRemove.KeyboardInputSite });
}
I execute this method just before disposing the WindowsFormsHost.
The second reason was RootSourceRelationManager.
This one gave me a headache. So I did a "Full" dotmemory profiling (before it was a sampled one).
The result was strange, the memory leak disappeared.
The full profiling needs to be executed from Dotmemory and not from Visual Studio. That was the only difference.
After some research I found out that Microsoft.Visual.Design Tools.WpfTap.wpf was involved.
So it seems (I can't be sure) that executing from visual studio causes a memory leak (which is not that serious but a good thing to know).
In the end, after releasing a new test version of the software with the clean method, I no longer have a memory leak.

A proper way of opening new wpf windows

I was wondering if there is a more efficient way of opening a fresh window in WPF than how presented in code below :
WindowConfigureDatabase windowConfigureDatabse;
private void ButtonConfigureDatabase_Click(object sender, RibbonControlEventArgs e)
{
if (windowConfigureDatabase == null)
{
windowConfigureDatabase = new WindowConfigureDatabase();
}
windowConfigureDatabase.Clear();
windowConfigureDatabase.Show();
windowConfigureDatabase.WindowState = WindowState.Normal;
}
Where windowConfigureDatabase is the new window I want to open. windowConfigureDatabase.Clear(); just resets all the values to default - there aren't many of them to reset. I was wondering whether or not this is the proper way of opening new windows in wpf. The other path I was thinking of was just simply creating a new window on each button click (that way I don't have to clear values each time...) but I'm afraid of allocating too much memory if a user opens the window and closes it a lot of times as I'm not quite sure if garbage collector picks the window up on OnClose event.
So basically my question is - does the garbage collector pick my windows up after I close them during Closing/Closed event? If not, what would be the proper way of managing the window's memory manually? Would adding a
windowConfigureDatabase = null
on Closed/OnClosing event do well?
does the garbage collector pick my windows up after I close them
during Closing/Closed event?
Yes, if unreachable. Read up on this for a better idea.
Would adding a
windowConfigureDatabase = null
on Closed/OnClosing event do well?
Yes. Failing to do this will prevent the window from being garbage collected until windowConfigureDatabase is overwritten or the object containing it is collected.
The memory used by a window depends on its dimensions and how much memory it allocates to do what it needs to do. You generally don't need to worry about this unless you're creating tons of windows(~30+) and/or large volumes of data.
The fastest way to allocate is to allocate up front(ideally at startup) and reuse when possible. Fortunately with windows this is relatively easy. The idea is to hide instead of close, and only close when truly no longer needed.
Like this:
// In each window class or as a base class:
private bool isClosable = false;
protected override void OnClosing(CancelEventArgs args)
{
// Prevent closing until allowed.
if (!isClosable) {
args.Cancel = true;
Hide();
}
base.OnClosing(args);
}
// Call this when you want to destroy the window like normal.
public void ForceClose()
{
isClosable = true;
Close();
}

UWP Windows 10 App memory increasing on navigation

I have a UWP Windows 10 App and noticed the memory usage in task manager is increasing over time.
I stripped the App back and found the memory is increasing when the navigating pages. So I made a simple app with just a few pages to test and the memory is still increasing in this simple App. I have a MainPage that navigates a frame from Page1 to Page2 and back on a timer.
public sealed partial class MainPage : Page
{
private DispatcherTimer _timer;
private bool _page1Showing;
private bool _timerRunning;
public MainPage()
{
this.InitializeComponent();
_timer = new DispatcherTimer();
_timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
_timer.Tick += _timer_Tick;
}
private void _timer_Tick(object sender, object e)
{
GC.Collect();
this.rootFrame.BackStack.Clear();
this.rootFrame.ForwardStack.Clear();
if (_page1Showing)
{
this.rootFrame.Navigate(typeof(Page2));
_page1Showing = false;
}
else
{
this.rootFrame.Navigate(typeof(Page1));
_page1Showing = true;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (_timerRunning)
{
_timer.Stop();
_timerRunning = false;
}
else
{
_timer.Start();
_timerRunning = true;
}
}
}
Page1 and Page2 are empty pages with a grid with a background color so you can see the navigation. While this App runs the memory usage in task manager increases by around 1MB every 30 mins.
I have run the App using the memory diagnostics in VS2015 the Managed heap is as expected:
The heap is always increasing:
Comparing snapshots of the Heap shows:
I am confused what these McgInterop objects are? and why such a simple App is always increasing in memory usage. My main App needs to run for a long time (months+). Appreciate any help.
I have tried changing the pages NavigationCacheMode, if set to Required the pages are created once. If set to disabled the Pages are created every time, and I checked the finalizer is called as expected.
--
Edit: I added a button to start and stop the timer (updated the above). It seems that while the timer is running the memory usage in Task manager will increase, when the timer is stopped the memory usage eventually drops.
I measured the memory usage in task manager over a day starting and stopping the timer around every 2 hours as follows, it slowly increases and then drops at some point:
12.5 -> 17.1 -> 16.7 -> 13.9 -> 16.8 -> 22.5 -> 13.6 -> 14.6 -> 24.9 -> 15.2
So I guess everything is working fine? But I am not clear what is happening here, why is it increasing so much? When is it being free'd under what conditions?
Is the system delaying releasing memory while pages are navigating? when the user would normally be interacting with the screen?
Every time you navigate to a Page, you create a new instance of Page, but the previous Page is not disposed (even if the Page is already in the navigation stack).
To prevent multiple allocation of same page, set NavigationCacheMode="Enabled" attribute to the Page.
Also, to minimize the memory allocation, you must override method OnNavigatedTo and OnNavigatedFrom.
In OnNavigatedTo method:
Instantiate all memory intensive object or resources
Add all events handlers you need
starts all timers, tasks or threads
In OnNavigatedFrom:
Dispose all resources
Stops all timers, tasks or threads
Remove references from all heavy objects
Remove all events handlers
Only if you really need, call GC.Collect()
Can we see your xaml code? Are you using x:name in your xaml and is that being destroyed? If so that might cause your memory leak.
Look at this link if you are using x:name:
http://support.scichart.com/index.php?/News/NewsItem/View/21/wpf-xname-memory-leak--how-to-clear-memory-in-scichart
Of course a UWP may handle x:name differently...
I have seen the same problem on w8.1 with printingInline using charmBar it's consuming a lot of memory until crash of the application (1.5 GB). but normaly you don't need GC.colect() it's work automaticly .

Memory stack-up issue with Aforge and Windows Forms

I am experiencing a strange memory stack-up in my c# windows form program that occurs all the time on slow PCs, and when the windows form loses focus or is otherwise interrupted on faster PCs.
The program I have written uses Aforge to get images from my webcam, which I then display in an Aforge picturebox control (CurrImagePic in code) in the windows form. The images are switched into the picture box and then disposed at the camera's native framerate, so it appears as video to the user, not still images. The picture box is 1080x1920, but the space for it in the form is smaller and so I allow the user to scroll around the picture.
After about ~30 seconds of memory-stable operation on slower PCs, the problem begins. On faster PCs, the problem only occurs when holding down scroll bar arrows or clicking and dragging around either scroll bar, and if I lock the PC or bring up the Ctrl+Alt+Delete menu.
The problem itself is that memory used by the program starts to increase in very large chunks, leading to an out of memory crash. This is unstoppable on slower PCs, but on the faster PCs if you stop scrolling or return from the lock/Ctrl+alt+delete menu, the program stabilizes at the higher memory usage level. The memory that was accrued during scrolling or while in the lock menu is never collected by the garbage collector. I've even tried to put in a button that forces a GC.collect() when pressed, and it does not reduce this memory usage.
I've run perfmon and found that the memory increase is on the unmanaged heap, but I don't know if it's coming from bitmaps which are not being disposed or what it could be from. It's been impossible to track down since it does not occur except in the above conditions. I've tried various solutions (like moving my image processing out of the event handler and even using both global flags and a "lock" statement to try and ensure that only one thread or frame can access the image processing and displaying method at at time, but I have seen no change. In fact, I am now seeing some unexplained small jumps in memory usage that I wasn't seeing before I put in the lock and moved the processing out of the handler.
Has anyone run into situations like this? I am at a loss for what I need to fix, and I am not getting much help from the Aforge forums. I think the problem is based around my Aforge event handler and image processing method if it is in my code at all - but I also have a suspicion that this is something deeper in the windows form code that I am either misusing or that can't keep up with the demands of my code. Code below:
//Applicable Globals to this code snippet
private bool ALLOWFRAME = true;
private Object FRAMEKEY = new Object();
private VideoCaptureDevice COMPVID;
private Bitmap TMPLTCAP;
private System.Drawing.Image OLDIMAGE;
private bool RCRDPIC = false;
private void COMPVID_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
//Only process a frame when another is done processing
if (ALLOWFRAME == true)
{
ALLOWFRAME = false;
Bitmap PassFrame = AForge.Imaging.Image.Clone(eventArgs.Frame);
ProcessFrame(PassFrame);
PassFrame.Dispose();
}
}
private void ProcessFrame(Bitmap frameIn)
{
lock (FRAMEKEY)
{
if (OLDIMAGE != null) { OLDIMAGE.Dispose(); }
//Call comparison method if flag is set.
if (COMPON == true)
{
Difference TmpltFilter = new Difference(TMPLTCAP);
TmpltFilter.ApplyInPlace(frameIn);
OLDIMAGE = CurrImagePic.Image;
CurrImagePic.Image = AForge.Imaging.Image.Clone(frameIn);
OLDIMAGE.Dispose();
}
else
{
OLDIMAGE = CurrImagePic.Image;
CurrImagePic.Image = AForge.Imaging.Image.Clone(frameIn);
OLDIMAGE.Dispose();
//Toggle the flag back to false to show it's safe (i.e., comparisons have stopped)
//for the result-recording method to copy from the picture box if it is attempting to copy
if (RCRDPIC == true)
{
RCRDPIC = false;
}
}
ALLOWFRAME = true;
}
}
One approach that has often improved performance is to queue up he images in memory and use a timer control to dequeue/display them in a picture box. This way, you get control over proper disposal and allow the NewFrame event to return faster rather than being tied up in image processing.
Also, in the Timer_Tick event, try and do the following:
this.Timer.Stop();
Bitmap image = null;
var temp = this.PictureBox.Image;
lock (FRAMEKEY)
{
if (this.ImageQueue.Any())
{
image = this.ImageQueue.Dequeue();
if (temp != null) { temp.Dispose(); }
}
}
this.PictureBox.Image = image;
if (temp != null) { temp.Dispose(); }
this.Timer.Start();

Process does not close after closing the form

I have a first form that calls another one and then disappears (frm.visible = false).
This form should not come back after being called once, but it's the main form (the first one that appears when you launch the program). I am trying to make it so when you close the second form, both forms close, I have tried multiple things but all of them leave the process active.
This is the code that I use :
private void frmCreation_FormClosing(object sender, FormClosingEventArgs e)
{
frmProperties frm = new frmProperties();
frm.Dispose();
}
//I have also tried frm.Close() which also does not work
This code close the two forms, but the process remains active. How do I counter this?
Application.Exit() tells your App to close itself.
Environment.Exit(0) tells Windows to kill it.
I prefer the latter since it really closes your app no matter what.
Maybe you are looking for Application.Exit()?
I can believe the solution here is : Do not handle it.
If the process is still pending that means you are not disposing your resources properly.
Using Application.Exit() or asking the system to do it Environment.Exit(0) may be logged in the system as an error occurred and you are better to know how to properly close a process than relied on Application.Exit(), if you want to close a thread of your app you have to know how to collect those garbage.
You can re-implement the Dispose method to Dispose services, sockets, streams, almost everything that has a .Dispose available.
public class MyClass: IMyClass, IDisposable
{
private bool _disposed = false;
// ...
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// dispose your stuff you created in this class
// do the same for other classes
// some examples
/*
_webClient.Dispose();
_connector.DataAvailable -= ConnectorHasDataComing
_socket.Dispose();
_timer.Dispose();
_taskLogs.ForEach(x => {
x.Token.Cancel();
x.Task.Wait();
x.Task.Dispose();
});
*/
}
// dispose native events
_disposed = true;
}
If you use System.Threading.Thread or System.Threading.Tasks.Task or System.IO.MemoryStream (or other kind of Stream - Writer/Reader), and others that requires a CancellationTokenSource. If you created the ressource in the class when you are disposing the class, use the Token.Cancel() method to let it know its parent is being disposed and .Wait() for it before calling .Dispose()
public async Task Run(CancellationTokenSource cancellationTokenSource)
{
// ...
while (Running) {
if (cancellationTokenSource.IsCancellationRequested) return;
// ....
}
// ....
using (var reader = new WaveFileReader(tempFile))
{
reader.Position = 0;
await reader.CopyToAsync(fileWriter,81920, cancellationTokenSource.Token);
}
}
I found my issue using the Diagnostic Tools when my Debug was still pending on something after closing the app.
If you use CPU Usage you can click on Break All and it set a breakpoint.
You can then see profiler and find what are your top functions, you might find out that your form is disposed but you have a Thread or Task that invokes fields on your form.
For my case, I was using a filewriter and I implemented IDisposable in that class but it sometimes was about or actual doing a transfer of data between a filereader and itself using .copyTo so it was pending without throwing an exception.
After clicking on one the events, click on Go to Source code and place a breakpoint, you may see events that your code is stocked on.
Otherwise, you can use in the same tool the tab Memory Usage to take a snapshot and look at the Heap and Objects diff or the tab CPU Usage and look at a recorded Profile. If find my copyTo issue that way.
You can also run your app with Throw on all exceptions
while disposing make sure no one recalls the form or its instance.
Also, if you are using the form event _FormClosing
Make sure if you have a modal to cancel the form closing, return and set e.Cancel = true; but do not set e.Cancel = true if the form is closing. And do not call this.Close() in a _FormClosing() event that you are handling yourself.
After, you may .Dispose() your stuff, but make sure no Dispose methods call the form back like invoking components, since they are being disposed or already disposed.
For people that use the hack that sets the form in an var instance to have access to it anywhere, do not dispose it, otherwise you are disposing a form already disposed.

Categories