Chrille
Chrille

Reputation: 1453

Limit memory usage using CSharpScript interface

I have an application where I'm using a high number of CSharpScript instances to control the application. The problem I'm facing is that the memory usage depends heavily on what type of global object I'm using. If the global type is defined in my application assembly (huge assembly) the memory usage rises by about ~100MB for every compiled script. If I instead put the global type in a separate assembly I find the memory usage to rise by ~10MB for each script which is still a lot for the amount of scripts I'm using.

Is there any way to limit this memory usage when using the CSharpScript API?

Upvotes: 0

Views: 1613

Answers (2)

idanp
idanp

Reputation: 1122

I don't know what is your specific implementation but it might be possible for you to do this:

Instead of giving the data to your scripts using big heavy global object, you can let the script give your application only their logic:

instead of this csx file, with HeavyObject as global:

// script.csx:
HeavyObject.DoSomeWork();

you can write this csx, with no global param needed:

// betterscript.csx:
public class ScriptWork : IHaveWork
{
    Work(HeavyType obj)
    {
        obj.DoSomeWork();
    }
}
return new ScriptWork();

you need this interface in your app:

public interface IHaveWork
{
    void Work(HeavyType obj);
}

and the script should run with references to your application. You would receive from your script an instance of IHaveWork, and then you should call Work within your application.

Upvotes: 1

Bradley Uffner
Bradley Uffner

Reputation: 16991

What I believe is happening here is that your script directly references an object defined in the main application. Since the script is compiled in to a separate AppDomain, this causes that AppDomain to pull in its own local copy of things from the AppDomain of the main application. Since you have 100s of scripts, each in their own AppDomain your main assembly gets loaded 100s of times.

One way to avoid this is to have any interfaces between the scripts and the application pass through a "shim" object, which is a small class, defined in its own assembly, that can "serialize" data across that AppDomain boundary. That Shim class should inherit from MarshalByReferenceObject. This can be tricky and complex, because the shim can't pass any of the classes defined in the application, or it will "suck in" the main assembly just like before. Everything must be passed as classes defined in .NET.

The MarshalByReferenceObject as a base class allows the shim to cross the domain boundary without bringing in an entire copy of the assembly. More information can be found at https://msdn.microsoft.com/en-us/library/system.marshalbyrefobject(v=vs.110).aspx#Remarks

Upvotes: 2

Related Questions