Forum: IronRuby Memory Leak with Certain Script Exceptions

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
6beced7e1914e4ed0b7232c73e6eac43?d=identicon&s=25 Aaron Clauson (aaronc)
on 2008-07-06 04:09
Hi,

I use the IronRuby scripting engine in a long running server process and
came across an issue where the memory utilisation of the process started
steadily rising in line with a memory leak. The server process is
written in C# (no unmanaged code) and I spent a lot of time double
checking and profiling the application to try ensure there were no
circular references or static lists keeping hold of objects etc.

Eventually I started looking at the Ruby script processing and found
that when a script threw certain exceptions the memory utilisation on
the process would start steadily incrementing. It's not all exceptions,
syntax errors and method missing execeptions seem fine but
ArgumentOutOfRange or NullReferenceExceptions exhibit the behaviour. A
stack trace of such a call is shown below.

I checked the behaviour using the latest version from svn (6 Jul 2008).

System.ArgumentOutOfRangeException: startIndex cannot be larger than
length of string.
Parameter name: startIndex
   at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32
length, Boolean fAlwaysCopy)
   at _stub_##44143(Closure , CallSite , CodeContext , Object , Int32 )
   at Microsoft.Scripting.Utils.InvokeHelper`6.Invoke(Object arg0,
Object arg1, Object arg2, Object arg3, Object arg4)
   at Microsoft.Scripting.Utils.ReflectedCaller.InvokeInstance(Object
instance, Object[] args)
   at
Microsoft.Scripting.Actions.ActionBinder.UpdateSiteAndExecute[T](CodeContext
context, CallSite`1 site, Object[] args)
   at
Microsoft.Scripting.Actions.UpdateDelegates.Update2[T0,T1,TRet](CallSite
site, CodeContext context, T0 arg0, T1 arg1)
   at Initialize##44129(Closure , CodeContext )
   at Microsoft.Scripting.ScriptCode.Run(CodeContext context, Boolean
tryEvaluate)
   at Microsoft.Scripting.ScriptCode.Run(Scope scope, Boolean
tryEvaluate)
   at Microsoft.Scripting.ScriptCode.Run(Scope scope)
   at Microsoft.Scripting.SourceUnit.Execute(Scope scope, ErrorSink
errorSink)
   at Microsoft.Scripting.SourceUnit.Execute(Scope scope)
   at Microsoft.Scripting.Hosting.ScriptScope.Execute(String code)

Regards,

Aaron
Cb51033949ffccd982ae32c9f890f25a?d=identicon&s=25 Tomas Matousek (Guest)
on 2008-07-06 08:29
(Received via mailing list)
What does the script look like?

BTW: Circular references alone cannot cause memory leak. CRL GC handles
them right.

Tomas
6beced7e1914e4ed0b7232c73e6eac43?d=identicon&s=25 Aaron Clauson (aaronc)
on 2008-07-06 08:45
Tomas Matousek wrote:
> What does the script look like?

Hi Tomas,

The Ruby script could be a single line such as:

sys.DoMethod(1, 2, 3)

Where sys is an object from a custom .Net class that has been loaded and
executed as:

ScriptRuntime scriptRuntime = IronRuby.CreateRuntime();
ScriptScope rubyScope = scriptRuntime.CreateScope("IronRuby");
DialPlanHelper helper = new DialPlanHelper();
rubyScope.SetVariable("sys", helper);
rubyScope.Execute("sys.DoMethod(1, 2, 3)");

If the DoMethod is called with the correct parameters it works fine,
however if the wrong number of arguments are provided a
System.ArgumentOutOfRangeException is thrown and the memory leak occurs.

Regards,

Aaron
F983f0c990cba2fe743ef62a975ec99c?d=identicon&s=25 Curt Hagenlocher (Guest)
on 2008-07-07 03:04
(Received via mailing list)
Are you continuously evaluating new bits of Ruby code?  Is each
execution in its own ScriptScope?  In its own ScriptRuntime?
6beced7e1914e4ed0b7232c73e6eac43?d=identicon&s=25 Aaron Clauson (aaronc)
on 2008-07-07 10:23
Curt Hagenlocher wrote:
> Are you continuously evaluating new bits of Ruby code?  Is each
> execution in its own ScriptScope?  In its own ScriptRuntime?

Yes pretty much. I have a bunch of users who can all have their own
little bit of script (the scripts are used as a dial plan on a SIP Proxy
server). At the moment a new runtime and scope is generated on for each
call received so the code per call is the equivalent of:

ScriptScope rubyScope = null;

try
{
  ScriptRuntime scriptRuntime = IronRuby.CreateRuntime();
  rubyScope = scriptRuntime.CreateScope("IronRuby");
  DialPlanHelper helper = new DialPlanHelper();
  rubyScope.SetVariable("sys", helper);
  rubyScope.Execute(m_dialPlanScript);
}
finally
{
  rubyScope.RemoveVariable("sys");
  rubyScope = null;
}

I previously has the ScriptRuntime as a static object common across all
users thinking that that would make things quicker but since I've had
the porblems with memory leaking I've swapped that to being a local
variable as well.

The memory leak definitely only happens when the specific exceptions are
thrown. I can run 500 scripts containing an exception and increase the
process memory by 50MB. Running 500 scripts that don't generate an
exception does not budge the process memory.

Thanks,

Aaron
This topic is locked and can not be replied to.