I see what you mean Arild and I agree with you. I guess a leak is still a leak, though the only difference is how the memory is managed. In either case, DoEvents() does in fact leak, which is why it shouldn't be used. I am fairly certain the cause is from the exact scenario described by Arild with the static event assignment.
~Graham
[.net] Plug in Tom's Render Loop in a few seconds!
I have read a lot on the web about the loops and Application.DoEvents and I can't understand why is acceptable to have a memory increase with every call to Application.DoEvents(). Even more I noticed another behavior I cannot understand. If I called the Application.DoEvents from the main application thread the application would allocate only 100 KB. If called the Application.DoEvents from another thread the allocated memory increased with 1MB. I have tried to dispatch the messages by using the pInvoke functions instead of calling the Application.DoEvents and the allocated memory increased only by 300KB.
In the code below there are 2 parameters: launchThread int thread which when is true would call the Application.DoEvents from a new thread otherwise will call it from the main thread and sysDoEvents which when is true will call the Application.DoEvents otherwise will call my implementation of DoEvents. The results are:
launchThread = true and sysDoEvents = true the application will leak 1 MB
launchThread = false and sysDoEvents = true the app would leak only 100 KB
launchThread = true and sysDoEvents = false would produce a 300-400 KB leak
launchThread = false and sysSoEvents = false woud produce a 300-400 KB leak
Below you can see the C# code from Win Forms test application. Do you see any explanation why the behavior is so different when calling the Application.DoEvents from the main thread and from a new thread? Any thoughts are highly appreciated.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
namespace DoEventsTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnTest_Click(object sender, EventArgs e)
{
bool launchThread = true;
for (int i = 0; i < 1000; i++)
{
Test test = new Test();
if (launchThread)
{
Thread t = new Thread(new ThreadStart(test.Work));
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
}
else
test.Work();
GC.Collect();
GC.WaitForPendingFinalizers();
}
MessageBox.Show("Done");
}
}
class Native
{
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public int message;
public IntPtr wParam;
public IntPtr lParam;
public int time;
public int pt_x;
public int pt_y;
}
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PeekMessage(
ref MSG lpMsg,
IntPtr hwnd,
Int32 wMsgFilterMin,
Int32 wMsgFilterMax,
Int32 wRemoveMsg);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool TranslateMessage(ref MSG lpMsg);
[DllImport("user32.dll", SetLastError = true)]
public static extern Int32 DispatchMessage(ref MSG lpMsg);
}
class Test
{
private void DoEvents()
{
Native.MSG msg = new Native.MSG();
while (Native.PeekMessage(ref msg, IntPtr.Zero, 0, 0, 1))
{
Native.TranslateMessage(ref msg);
Native.DispatchMessage(ref msg);
}
}
public void Work()
{
bool sysDoEvents = true;
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(50);
if (sysDoEvents)
System.Windows.Forms.Application.DoEvents();
else
{
DoEvents();
}
}
}
}
In the code below there are 2 parameters: launchThread int thread which when is true would call the Application.DoEvents from a new thread otherwise will call it from the main thread and sysDoEvents which when is true will call the Application.DoEvents otherwise will call my implementation of DoEvents. The results are:
launchThread = true and sysDoEvents = true the application will leak 1 MB
launchThread = false and sysDoEvents = true the app would leak only 100 KB
launchThread = true and sysDoEvents = false would produce a 300-400 KB leak
launchThread = false and sysSoEvents = false woud produce a 300-400 KB leak
Below you can see the C# code from Win Forms test application. Do you see any explanation why the behavior is so different when calling the Application.DoEvents from the main thread and from a new thread? Any thoughts are highly appreciated.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
namespace DoEventsTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnTest_Click(object sender, EventArgs e)
{
bool launchThread = true;
for (int i = 0; i < 1000; i++)
{
Test test = new Test();
if (launchThread)
{
Thread t = new Thread(new ThreadStart(test.Work));
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
}
else
test.Work();
GC.Collect();
GC.WaitForPendingFinalizers();
}
MessageBox.Show("Done");
}
}
class Native
{
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public int message;
public IntPtr wParam;
public IntPtr lParam;
public int time;
public int pt_x;
public int pt_y;
}
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PeekMessage(
ref MSG lpMsg,
IntPtr hwnd,
Int32 wMsgFilterMin,
Int32 wMsgFilterMax,
Int32 wRemoveMsg);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool TranslateMessage(ref MSG lpMsg);
[DllImport("user32.dll", SetLastError = true)]
public static extern Int32 DispatchMessage(ref MSG lpMsg);
}
class Test
{
private void DoEvents()
{
Native.MSG msg = new Native.MSG();
while (Native.PeekMessage(ref msg, IntPtr.Zero, 0, 0, 1))
{
Native.TranslateMessage(ref msg);
Native.DispatchMessage(ref msg);
}
}
public void Work()
{
bool sysDoEvents = true;
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(50);
if (sysDoEvents)
System.Windows.Forms.Application.DoEvents();
else
{
DoEvents();
}
}
}
}
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement