Re: memory leak using system.windows.forms.timer
- From: Gestalt <sspenning@xxxxxxxxx>
- Date: Thu, 12 Feb 2009 17:47:55 -0800 (PST)
On Feb 12, 3:05 pm, Gestalt <sspenn...@xxxxxxxxx> wrote:
On Feb 12, 10:50 am, "Cor Ligthert[MVP]" <Notmyfirstn...@xxxxxxxxx>Here is the latest test app. No timers, just a GUI button to call the
wrote:
Gestalt,
As you where giving typical problems as there are often with
system.timers.timer,my first gues was that the problem was in that.
However the subject says clearly system.windows.forms.timer
However, in your code is the system.timer.timer
(Are you busy with a service, because that is for what the where the
system.timers.timer is.
Cor
"Gestalt" <sspenn...@xxxxxxxxx> wrote in message
news:9a569c48-ead1-4b71-a820-5cb51d58be94@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
On Feb 11, 4:56 pm, Tom Shelton <tom_shel...@xxxxxxxxxxxxxxxxxx>
wrote:
On 2009-02-11, Gestalt <sspenn...@xxxxxxxxx> wrote:
I'm working on a small application using the
system.windows.forms.timer. The intent is to set an interval and on
the tick event fire a function that returns the number of workstation
objects that reside in a specific OU in Active Directory.
On the surface the application runs great. Under the surface, it's a
different story. I've found that every time the tick calls a trivial
subroutine, memory leaks. I've tried summoning garbage collection
periodically but that has not resulted in any improvement in memory
consumption. Left overnight the app will bloat to over half a gig of
RAM consumed (and continuing to climb). I have tested it on XP Pro,
Vista SP1 (x64) and Windows Server 2008 (x86).
The subroutine that appears to be leaking is here as follows:
Private Sub CheckComputers()
Dim intCount As Integer
intCount = CountADComputers(My.Settings.strTargetDN)
If intCount > My.Settings.intTargetCount Then
intTrigger = 1
Else
intTrigger = 0
End If
intCount = Nothing
End Sub
I have found that if I substitute the call to the CountADComputers
subroutine with a static number (e.g. 1) I still leak memory. If I
leave this subroutine out of the program then the leak stops (and
obviously the program does nothing).
What else does the timer do? Only calling this CheckComputers sub? It
seems
highly unlikely that simply calling a sub is going to cause a memory leak.
This generally means unreleased references..
Hmmm... intTrigger - I dont see that declared in the timer routine, so is
this
being monitored somewhere? another thread? Need more info :)
By the way, setting the intCount to nothing - is basically useless in the
above, and in fact will probably optimized out of the final code anyway.
There is almost no reason to ever explicitly set any object to nothing in
VB.NET (actually this was true in VB6 as well). The major exceptions are
module and class level fields - local values, well your mostly just
wasting
your time and cycles :)
For the record, here is the CountADComputers subroutine:
Public Function CountADComputers(ByVal strADPath As String) As
Integer
Dim intCount As Integer
Dim entry As New DirectoryServices.DirectoryEntry(strADPath)
Dim mySearcher As New
System.DirectoryServices.DirectorySearcher(entry)
mySearcher.PageSize = 1000
mySearcher.Filter = "(objectClass=Computer)"
intCount = mySearcher.FindAll.Count
mySearcher.Dispose()
mySearcher = Nothing
entry.Dispose()
entry = Nothing
Return intCount
End Function
If your using .NET 2.0 (2005) or higher, then I believe I would write this
routine more like:
Public Function GetADComputers (ByVal strADPath As String) As Integer
Using entry As New DirectoryServices.DirectoryEntry(strADPath), _
mySearcher As new DirectoryServices.DirectorySearcher(entry)
With mySearcher
.PageSize = 1000
.Filter = "(objectClass=Computer)"
End With
Return mySearcher.FindAll.Count
End Using
End Function
If your not using 2005, then I might suggest using Try/Finally to ensure
that
dispose is called even if an exception is thrown (the above is really
syntactic sugar for Try/Finally).
Can anyone think of a reason why this would be causing a problem?
Not from the information/code provided. You might want to create a short,
but
complete program (http://www.yoda.arachsys.com/csharp/complete.html) that
demostrates the issue. Or better yet, you might look at getting a memory
profiler tool - such as Ants Profiler. These kinds of tools are invaluable
when trying to track down stuborn memory leaks...
--
Tom Shelton
I've tried your suggestions and narrowed things down a bit.
First, I was wrong about the AD query not being the culprit. It is
the source of the leak. It turns out that my copy of Visual Studio
isn't always completing the build process when I tell it to do so.
Thus when I thought I was testing the code with AD query commented out
it was in fact still part of the cycle. I'm doing my dev from another
install now and the builds are coming out correctly.
I am evaluating the Ants Profiler app and I think it has identified
the source of the problem. Every time the Directory Searcher returns
new results, those results remain in memory even when the searcher is
disposed of. Garbage collection does not clean up the data, even when
called manually or through the Ants Profiler interface.
The only way I have found to mitigate this problem is to refine the
scope of my search to only return a single attribute from the computer
objects. This has slowed the growth in memory considerably but it has
by no means stopped it. I ran a test app overnight and it went from
7Meg RAM at start to 160Meg.
Here is a demonstrative app illustrating the problem. To test it an
active directory domain will need to be provided.
Imports System.Timers
Module Module1
Private MasterTimer As System.Timers.Timer
Dim strPath As String = "LDAP://<your domain here>"
Dim intTrigger As Integer = 0
Sub Main()
MasterTimer = New System.Timers.Timer(500)
AddHandler MasterTimer.Elapsed, AddressOf Tick
MasterTimer.Enabled = True
Console.WriteLine("Press the Enter key to exit the program.")
Console.ReadLine()
End Sub
Private Sub Tick(ByVal source As Object, ByVal e As
ElapsedEventArgs)
CheckComputers()
End Sub
Private Sub CheckComputers()
If GetADComputers(strPath) > 1 Then
Console.WriteLine("Alert State Detected: " & GetADComputers
(strPath) & vbCrLf)
intTrigger = 1
Else
Console.WriteLine("Situation Normal " & GetADComputers
(strPath) & vbCrLf)
intTrigger = 0
End If
End Sub
Public Function GetADComputers(ByVal strADPath As String) As
Integer
Using entry As New DirectoryServices.DirectoryEntry
(strADPath), mySearcher As New DirectoryServices.DirectorySearcher
(entry)
With mySearcher
.PageSize = 1000
.Filter = "(objectClass=Computer)"
.PropertiesToLoad.Add("sAMAccountName")
End With
Return mySearcher.FindAll.Count
End Using
End Function
End Module
Does anyone have any idea what I can do to stop the leak entirely?
Should I address this to the ADO group?
You are correct, I have shifted from system.windows.forms.timer to
system.timers.timer for the purposes of illustrating the problem. It
was suggested that I post a simple code example illustrating the
problem. It appears that the problem occurs using either timer. The
key issue appears to be that garbage collection is not cleaning up the
results retrieved by the AD search contained in the GetADComputers
function. I'll try some additional tests using the same function
repeatedly without benefit of a timer and see if the results still
build up in memory.
Any other additional suggestions are greatly appreciated.
AD query. The leak is definitely in the AD search and not in the
timer.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Label1.Text = GetADComputers("LDAP://<your domain here>")
End Sub
Public Function GetADComputers(ByVal strADPath As String) As Integer
Using entry As New DirectoryServices.DirectoryEntry(strADPath),
mySearcher As New DirectoryServices.DirectorySearcher(entry)
With mySearcher
.PageSize = 1000
.Filter = "(objectClass=Computer)"
End With
Return mySearcher.FindAll.Count
End Using
End Function
Using the Windows Task Manager, I can watch the memory consumed by the
application go up each time the button is pressed. Garbage collection
does not appear to have any impact.
I've used the Ants Profiler to peek into the RAM data and it appears
to be filled with the results from the AD search. I can mitigate this
by reducing the attributes returned since I am only looking for a
headcount but this really only slows the problem.
Is there any way I can flush these results from memory?
.
- Follow-Ups:
- Re: memory leak using system.windows.forms.timer
- From: Michel Posseth [MCP]
- Re: memory leak using system.windows.forms.timer
- References:
- memory leak using system.windows.forms.timer
- From: Gestalt
- Re: memory leak using system.windows.forms.timer
- From: Tom Shelton
- Re: memory leak using system.windows.forms.timer
- From: Gestalt
- Re: memory leak using system.windows.forms.timer
- From: Cor Ligthert[MVP]
- Re: memory leak using system.windows.forms.timer
- From: Gestalt
- memory leak using system.windows.forms.timer
- Prev by Date: Re: Lightweight WebBrowser needed
- Next by Date: How to enumerate all the network connection names?
- Previous by thread: Re: memory leak using system.windows.forms.timer
- Next by thread: Re: memory leak using system.windows.forms.timer
- Index(es):