Friday, July 22, 2011

IE Page Recycle code snip - Stop gap means to keep IE9 from eating all my RAM...

Given:

  • IE9 has a few memory leaks, whereas if a page/tab is left loaded it will continue to consume RAM
  • My IE9 use case leaves pages/tabs open for hours to days.
  • I've seen IExplore.exe process sessions (which host 1 to X pages/tabs) consume 500, 1, 2GB of RAM.
  • If  those hog sessions are end tasked, the main/primary/IE9 overlord session will start a new process and reload those pages, and their RAM usage will be inline with other sessions/pages

Yesterday I finally got tired of this and decided it was time to break out VS and do something about it.

 

While this project, as simple as it is, isn't ready for sharing here's how I did it.

a) Project is a console app

b) I'm using Windows 7 Task Scheduler to run the exe every 15 minutes

c) Using WMI, the code looks for any iexplore.exe sessions

d) If that session has "SCODEF" in its command line AND.... (These are the sessions being "watched" by the IE9 Overlord session, i.e. the iexplore.exe with the PID of 9976)

image

d) If that session has a WorkingSetSize greater than 300K AND

e) If that session is at least 4 hours old THEN

f) Terminate/kill it.

Wash, rinse, repeat.

 

This is the entire source.

Imports System.Management

Module IEPageRecycler
Public Sub RecyclePages()
Dim searcher As New ManagementObjectSearcher("SELECT * FROM Win32_Process WHERE Name='iexplore.exe'")

For Each wp As ManagementObject In searcher.Get()

If DirectCast(wp("WorkingSetSize"), UInt64) > 300000000 And
wp("CommandLine").ToString.Contains("SCODEF") And
ManagementDateTimeConverter.ToDateTime(wp("CreationDate").ToString).AddHours(-4) <= Now Then

My
.Application.Log.WriteEntry("Killing IE Process " & Now & " Command Line:" & wp("CommandLine").ToString & " Created:" & ManagementDateTimeConverter.ToDateTime(wp("CreationDate").ToString) & " WorkingSet:" & wp("WorkingSetSize").ToString)

Dim x(2) As Object
wp.InvokeMethod("Terminate", x)

End If

Next

End Sub

Sub
main()
My.Application.Log.WriteEntry("Starting Recycling Pages " & Now)
Try
RecyclePages()

Catch ex As Exception
My.Application.Log.WriteException(ex)
End Try
End Sub

End Module

Yeah, it's FUGLY, but it seems to be getting the job done. I'm going to use it for a week or so and if all's well, I'll clean it up and share the project somewhere...


To Do:

  • Command Line Parameter to set memory threshold and process age
  • Automate Windows Task Scheduler task creation
  • A UI might be nice, like a history of runs, terminates, etc, or worse case an easy link to the log file
  • Maybe fine tune the leaky processes discovery, that instead of thresholds like now, track usage over time and only kill those that grow X% over a period or something like that

A couple things I learned:

  • System.Diagnostics.Process doesn't have a means to access a given process' command line (that I could find at least).
  • The right way to convert WMI Dates to a standard .Net DateTime is via System.Management.ManagementDateTimeConverter.ToDateTime
  • Getting the Windows 7 Task Scheduler to run a task every 15 minutes seems to be tricky. I really really, I mean really, hate zombie processes/tasks. Those process that run, but only do stuff every XX hours/days/weeks. The Windows Task Scheduler "should" be able to execute said tasks as needed, thereby no require the constant execution of them. In short, run, do your stuff and then get out of my CPU. But the problem I'm having is trying to get a task to run every 15 minutes. This shouldn't be hard, but it's nowhere near intuitive to setup/configure.

No comments: