Wednesday, November 26, 2003 12:23 AM
richard
Self-shrinking WorkingSet for your C# app
This is an interesting idea that makes use of System.Threading and System.Diagnostics to poll the provided process (or current process) and manually attempt to reduce the WorkingSet (the memory actually reserved by Windows for the process).
Of course my implementation could use a bit of tweaking (to say the least - I definately don't need a worker thread in there!). Finally I should issue this VERY STRONG DISCLAIMER: Direct manipulation of the WorkingSet or any aspect of memory management should not be up to your application, but left to .NET and the OS, this sample only demonstrates the power of the GC class. .NET applications will respond to system memory pressure - you don't need to worry about managing this. Anyway, here's the code:
using System;
using diag = System.Diagnostics;
using System.Threading;
using time = System.Timers;
namespace Ral
{
public class WorkingSetModerator : MarshalByRefObject
{
public WorkingSetModerator(diag.Process targetProcess, int proposedMaximum)
{
_targetProcess=targetProcess;
_memoryWatermark=proposedMaximum;
_targetProcess.MaxWorkingSet = new IntPtr(_memoryWatermark);
}
public WorkingSetModerator(int proposedMaximum) : this(diag.Process.GetCurrentProcess(), proposedMaximum) {}
private int _memoryWatermark;
private Thread _workerThread;
private diag.Process _targetProcess;
private time.Timer _timer;
private static object syncRoot=new object();
private void pollingMethod(object sender, time.ElapsedEventArgs e)
{
lock(syncRoot)
{
if(_workerThread==null || ((int)(_workerThread.ThreadState & (ThreadState.Unstarted | ThreadState.Stopped)))>0)
{
_workerThread=new Thread(new ThreadStart(ReduceWorkingSet));
_workerThread.IsBackground=true;
_workerThread.Priority = ThreadPriority.BelowNormal;
_workerThread.Start();
}
}
}
private double _interval=10000;
public double Interval
{
get
{
if(_timer!=null && _interval!=_timer.Interval)
_interval=_timer.Interval;
return _interval;
}
set
{
_interval=value;
if(_timer!=null && _interval!=_timer.Interval)
_timer.Interval=value;
}
}
public void ReduceWorkingSet()
{
if(_targetProcess!=null && !_targetProcess.HasExited)
{
if(_targetProcess.WorkingSet>=_memoryWatermark)
_targetProcess.MaxWorkingSet = new IntPtr(_memoryWatermark);
}
}
public void Start()
{
_timer=new time.Timer();
_timer.AutoReset=true;
_timer.Interval = _interval;
_timer.Elapsed +=new System.Timers.ElapsedEventHandler(pollingMethod);
_timer.Start();
}
public void Stop()
{
if(_timer!=null)
{
_timer.Stop();
_timer=null;
}
}
}
}