Memory Leak?

Feb 11, 2014 at 10:03 PM
I think I may have found a memory leak? I am able to reproduce it every time. I created a WPF app with a button and a progress bar. The code for the button is:
  Task<int> scriptTask = new Task<int>(() =>
  {

    string scriptPath = @".\test.js";

    if (String.IsNullOrEmpty(scriptPath) || !System.IO.File.Exists(scriptPath))
    {
      return -1;
    }

    _scriptEngine = new ScriptEngine();
    _scriptConsole = new Jurassic.Library.FirebugConsole(_scriptEngine);
    _scriptEngine.SetGlobalValue("console", _scriptConsole);

    for (int cnt = 0; cnt < 10000; ++cnt)
    {
      StringWriter output = new StringWriter();
      StringReader script = new StringReader(File.ReadAllText(scriptPath));
      _scriptConsole.Output = new TextWriterConsole(output);
      try
      {
        // Run Script
        ReaderScriptSource src = new ReaderScriptSource(script);
        _scriptEngine.Execute(src);
      }
      catch (Exception ex)
      {
        output.Write(ex.Message);
        output.Write(ex.StackTrace);
      }
      finally
      {
        script.Dispose();
      }

      string ret = output.ToString();
      output.Dispose();
      ReportProgress(cnt);
    }
    return 0;
  });
  scriptTask.Start();
  await scriptTask;
  if (scriptTask.Result == -1)
  {
    MessageBox.Show("Script file not found");
  }
The ReportProgress method looks like this:
  if (pgProgress.Dispatcher.CheckAccess())
  {
    pgProgress.Value = progress; 
  }
  else
  {
    pgProgress.Dispatcher.Invoke(
        System.Windows.Threading.DispatcherPriority.Normal,
        new IntChanger(this.ReportProgress), progress);
  }
The TextWriterConsole class is:

internal class TextWriterConsole : IFirebugConsoleOutput
{
private TextWriter _writer;

public TextWriterConsole(TextWriter tw)
{
  _writer = tw;
}

public void Clear()
{
  throw new NotImplementedException();
}

public void EndGroup()
{
  _writer.WriteLine("]");
}

public void Log(FirebugConsoleMessageStyle style, object[] objects)
{
  foreach (object obj in objects)
  {
    _writer.Write(obj);
  }
}

public void StartGroup(string title, bool initiallyCollapsed)
{
  _writer.WriteLine(String.Format("{0} [", title));
}
}

and the ReaderScriptSource looks like this:

class ReaderScriptSource : ScriptSource
{
private TextReader _reader;
private String _path;

public ReaderScriptSource(String path)
{
  _path = path;
  _reader = new StreamReader(_path);
}

public ReaderScriptSource(TextReader rdr)
{
  _path = "";
  _reader = rdr;
}

public override string Path
{
  get
  {
    return _path;
  }
}

public override TextReader GetReader()
{
  return _reader;
}
}

Each time I press the run button it picks up maybe 10 Mb. Obviously that is to be expected. But then as it finishes if you press Run again you will see that it walks up more and more memory. I am hoping that someone will catch something that I am doing wrong on the execution.

Pat O
Feb 11, 2014 at 11:33 PM
Edited Feb 11, 2014 at 11:34 PM
It is most likely this portion of your code:
      StringWriter output = new StringWriter();
      StringReader script = new StringReader(File.ReadAllText(scriptPath));
      _scriptConsole.Output = new TextWriterConsole(output);
      try
      {
        // Run Script
        ReaderScriptSource src = new ReaderScriptSource(script);
        _scriptEngine.Execute(src);
      }
I believe opening a file and reading all the contents each time is doing it. Since the file contents are presumably not changing you can put that stuff outside of the loop.
Feb 12, 2014 at 10:41 AM
Thanks for the observation. I created this program as an example. We are using scripting to test a piece of hardware we make. The hardware is on a network. When a packet comes in we run a script (one of many depending on the packet) to decide how to respond. It works well except we run out of memory on the test machine after a couple of hours. I had assumed the issue was with our API or driver so I wrote C# code to do what one of the more common scripts does. I was surprised (happily) to find no memory leak. So I built this example and was able to see the leak.
If there is something in the loop that I am doing poorly please let me know so I can resolve it. Also is there a way I can compile a script once and then run it over and over?
Feb 12, 2014 at 2:54 PM
Thanks for focusing my attention on the loop. The issue was that I was not disposing of the reader within the ReaderScriptSource. The problem is resolved. There is no memory leak in Jurassic that I can see. Thanks for a great tool. I will take the precompiled script question to a different thread.

Pat O