I haven't tested it but I suspect your problem is related to maintaining
isolation between your AppDomains. The way you have written your
code, the AppDomainTesting.TestEngine object is still being attached to your
primary AppDomain because of the CreateInstanceAndUnwrap call (and cast)
which is returning a (proxy) TestEngine object. Although it is a proxy, the
primary AppDomain still attaches to the assembly as metadata is required.
To solve this, an indirection solution (yuck) where the primary AppDomain
has NO knowledge of the assembly is required (class factory and invoke by
interface?).
Eric Gunnerson has recently written an article on dynamic assemblies on MSDN
which may help (sorry can't find the reference).
For this reason, I can't see how the AppDomain recycling scheme supplied by
MS in the thread of 15 July 2002 could work. Has anyone actually
managed to implement it successfully - how?
Regards,
Baddabing
"Trent" <noj...@mail.com> wrote in message
news:u3e06BoWCHA.436@tkmsftngp10...
> I have been working on loading and unload the VSA Engine into AppDomain to
> reduce the amount of memory usage in my application. I have built a test
> environment that will create and unload a VSA Engine into a AppDomain.
> While this reduces the amount of memory used compared to simple creating
and
> destroying the VAS Engine in the one domain, I still have an increase in
> memory.
>
> Have I set up the configuration for the domain incorrectly or is this the
> wrong way.
>
> I have attached the project and the code it anybody would like to test it.
> You will notice an increase in memory if the engine is complied.
>
> Test (With a for loop of 100)
> Without Compile Memory Usage = 15,000 k
> With compile Memory usage = 30,000 K
>
> While these memory values are low, it cause problems in the production
> environment when the number of engines and complexity of the script
> increase.
>
> Thanks
>
> using System;
> using System.Reflection;
> using System.Windows.Forms;
> using System.Collections;
> namespace AppDomainTesting
> {
> /// <summary>
> /// Summary description for Class1.
> /// </summary>
> class Class1
> {
> /// <summary>
> /// The main entry point for the application.
> /// </summary>
> [STAThread]
> static void Main(string[] args)
> {
> for(int i=0; i<100; i++)
> {
> AppDomain appDomain = null;
> AppDomainSetup setup = new AppDomainSetup();
> AppDomainSetup appDomainSetUp = new AppDomainSetup();
>
> Console.WriteLine("Insatance = "+i.ToString());
> try
> {
>
> appDomain =
>
AppDomain.CreateDomain(System.Guid.NewGuid().ToString(),null,appDomainSetUp)
> ;
>
> string assemblyName = Assembly.GetAssembly(
> typeof(AppDomainTesting.ScriptEngine) ).FullName;
>
> AppDomainTesting.TestEngine test =
>
(AppDomainTesting.TestEngine)appDomain.CreateInstanceAndUnwrap(assemblyName,
> "AppDomainTesting.TestEngine");
> //comment out the next line and memory usage will be lower
> test.Compile();
> test.Run();
>
> }
> catch(System.Exception err)
> {
> string error = err.ToString();
> System.Windows.Forms.MessageBox.Show(error);
> }
> finally
> {
> if(appDomain != null)
> AppDomain.Unload(appDomain);
> }
>
> }
>
> Console.WriteLine("Total Memory =" +
GC.GetTotalMemory(true).ToString());
> Console.WriteLine("Press Enter To End");
> if(Console.Read()>0)
> return;
> }
> }
> public class TestEngine : System.ComponentModel.Component
> {
> private ScriptEngine engine;
> public TestEngine()
> {
> engine = new ScriptEngine();
> }
> public void Compile()
> {
> engine.Compile();
> }
> public void Run()
> {
>
> if(engine.IsCompiled)
> {
> engine.Run();
>
> string strNamespace = engine.RootNamespace;
> string FullName = strNamespace +".script";
>
> // Get the method from the type
> Type ModType = engine.Assembly.GetType(FullName,true,true);
> System.Reflection.MethodInfo method = ModType.GetMethod("main");
> if (method != null)
> method.Invoke(null,null);
> }
> }
> }
> public class ScriptEngine : Microsoft.VisualBasic.Vsa.VsaEngine
> {
> public ScriptEngine()
> {
> this.RootMoniker = "MemoryTesting://script";
> this.Site = new VsaBaseSite();
> this.InitNew();
> this.RootNamespace = "scriptcode";
> this.Name = "scriptcode";
> Microsoft.Vsa.IVsaReferenceItem systemRef=
>
(Microsoft.Vsa.IVsaReferenceItem)this.Items.CreateItem("system.dll",Microsof
> t.Vsa.VsaItemType.Reference, Microsoft.Vsa.VsaItemFlag.None);
> systemRef.AssemblyName = "System.dll";
> Microsoft.Vsa.IVsaCodeItem code=
>
(Microsoft.Vsa.IVsaCodeItem)this.Items.CreateItem("main",Microsoft.Vsa.VsaIt
> emType.Code, Microsoft.Vsa.VsaItemFlag.Module);
> code.SourceText= this.script;
>
> }
> private string script = "Option Strict Off\n"+
> "Option Explicit Off\n"+
> "Imports System\n"+
> "Imports System.Windows.Forms\n"+
> "Public Module script\n"+
> "Sub main\n"+
> //"MessageBox.Show(\"Testing\")\n"+
> "Console.WriteLine(\"Testing \" & DateTime.Now.ToLongTimeString())\n"+
> //"MessageBox.Show(\"Testing\")\n"+
> "End Sub\n"+
> "End Module\n";
> }
> public class VsaBaseSite :Microsoft.Vsa.IVsaSite
> {
>
>
> #region Implementation of IVsaSite
> public object GetEventSourceInstance(string itemName, string
> eventSourceName)
> {
> return null;
> }
> public object GetGlobalInstance(string name)
> {
> return null;
> }
> public void Notify(string notify, object info)
> {
>
> }
> public bool OnCompilerError(Microsoft.Vsa.IVsaError error)
> {
> Console.WriteLine(error.ToString());
> return true;
> }
> public void GetCompiledState(out byte[] pe, out byte[] debugInfo)
> {
> pe = null;
> debugInfo = null;
>
> }
>
> #endregion
> }
> }
>
>
>
>
>
Thanks for the ideas. I have not been successfully able to implement them
yet, but I'm still trying. The link to the article you mention; (watch for
word wrap)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/htm
l/csharp05162002.asp
another usefully article can be found at Codeproject
http://www.codeproject.com/csharp/livecodedotnet.asp
If anybody has been successful in implementing AppDomain recycling scheme
using the VSA engine please let me know
Thanks
Trent
"Baddabing" <re...@togroup.com> wrote in message
news:#H9Ppw6XCHA.2652@tkmsftngp10...
Exactly - that's the idea. One point though, is that typically the
interface and class factory would be created in their own DLL.
The really bad news is that you will find that memory continues to be
consumed when instantiating (thats all it takes) the VB engine in a second
AppDomain, even after that second AppDomain is unloaded. This is not the
case for the JScript engine.
( MS - I would really like to know the cause of this VB engine unload memory
issue - is it related to there being no mechanism to fully unload a
domain-neutral assembly?)
This flaw I think prevents the use of the VB engine in this scenario.
Microsoft, I believe, have stated that it was never intended the use of a
second AppDomain solution to solve the assembly unload dilemma. The whole
point of their solution is access to live objects and events which is
negated by having to use a second AppDomain.
The necessity to use a second AppDomain in a compile many times scenario,
and then pay the price in regards to live objects and events, means that
Script for the Dotnet framework remains suitable only for a compile once/run
many times scenario IMHO.
Regards,
Baddabing
"Trent" <noj...@mail.com> wrote in message
news:#WVWVFDYCHA.444@tkmsftngp12...
> I have attached a working copy of the of AppDomain recycling scheme that I
> put together from the articles. hopefully this is the right way???
>
> Trent
>
>
> "Trent" <noj...@mail.com> wrote in message
> news:OIYfvcAYCHA.2452@tkmsftngp09...
This isn't a managed memory issue.
Simply instantiating the VB Engine in a second AppDomain, and then
successfully unloading that AppDomain, leaves allocated system memory. As
mentioned this is not visibly the case for the JScript engine or for an
arbitrary assembly generated through the Reflection.Emit namespace into a
non-primary domain.
On my system, creating an instance of the VB engine into a second AppDomain
and unloading the AppDomain grows system memory usage by (very) approx.
4.5mb every 100 instantiations.
All I can think of, is that this is a domain-neutral assembly issue and the
VSA VB code (domain-neutral assemblies statics and CLR data structures are
freed on an AppDomain unload but not code) is huge or something. Seems
unlikely to me, but it could be tested by implementing ones own CLR host
with CorBindToRuntimeEx specifying no domain-neutral assemblies (other than
mscorlib.dll).
As per my previous message I think that having to use a second AppDomain
(for a compile many/run few scenario) negates the real advantages of Script
for the .Net Framework (live objects and events). Furthermore, I'd hazard a
guess that the script team have let out a few expletives about the CLR's
inability to unload an assembly. If one could - scripting would be soooo
schweeet.
But would be useful to know if anyone has implemented a VB engine AppDomain
recycling scheme where system memory doesn't grow as I describe? Anyone
have any other thoughts or a solution?
Regards,
Baddabing
"JM Servera" <soyla...@yahoo.es> wrote in message
news:#tIchwLYCHA.3736@tkmsftngp08...
BTW thanks for the allocation profiler link - didn't know about it and it
looks excellent.
Thanks,
Baddabing
"JM Servera" <soyla...@yahoo.es> wrote in message
news:#tIchwLYCHA.3736@tkmsftngp08...
"Baddabing" <re...@togroup.com> escribió en el mensaje
news:O8JB6#PYCHA.2452@tkmsftngp11...
I've actually been going nuts over this AppDomain issue and am about to give
up. However, I believe I was wrong in stating that this is only an issue
with the VB VSA engine.
My experiments lead me to now believe that continually instantiating
(different each time) assemblies into a secondary AppDomain which is then
unloaded, leads to a substantial increase in system memory use - recoverable
only at end of process. This is the case even if interaction between the
default and secondary AppDomain is limited to invoking of methods through an
interface returned through a factory created instance of the assembly in the
second AppDomain - i.e. the default AppDomain knows nothing about the remote
assembly other than through that interface.
This doesn't really impact on generating a small number of dynamic
assemblies for things like plugins, but sure does for scripting where one
might want to generate and load hundreds of assemblies.
Would be really grateful if someone could show me I'm wrong?
Your project sounds interesting - is it web based?
Best regards,
Baddabing
"JM Servera" <soyla...@yahoo.es> wrote in message
news:#YyPAjtYCHA.2260@tkmsftngp09...
Greetings from Mallorca,
JM
"Baddabing" <re...@togroup.com> escribió en el mensaje
news:OskTnUvYCHA.952@tkmsftngp12...
"JM Servera" <soyla...@yahoo.es> wrote in message
news:uWcuxU6YCHA.1152@tkmsftngp10...
I hope Microsoft addresses this soon :(.
BTW, check out the DynamicJava project
(http://koala.ilog.fr/djava/#overview). It supports dynamic interpretation
of Java. C# needs something like this :|.
::Tum
"Baddabing" <re...@togroup.com> wrote in message
news:OskTnUvYCHA.952@tkmsftngp12...
I've also tried to comment the inner code of the "if" without any luck, so,
I'm sure that the method that is leaking is the "Compile" one.
In any other case I've tested AppDomain loading/unloading works fine, it
just begins leaking
I really do need a solution or workaround for this leak.
"Miljan Mitrovic" <miljan@pexim(.dot.)co(.dot.)yu> escribió en el mensaje
news:ulp0o77YCHA.2580@tkmsftngp12...
Are you sure that this is really the issue? Commenting out the compile
means that the SAME assembly is continually getting loaded into a recycled
appdomain. Definately no memory problems with that.
The real issue is whenever a DIFFERENT assembly is loaded (each time) into a
recycled appdomain. I think you will see this behaviour with ANY
dynamically generated assembly, whether through codedom or vsa.
This is the (current) .NET VSA scripting paradox - you can use scripting if
you don't have to compile many scripts (or you can stop and restart the
process). But then why use scripting?
What do you think - can you try it?
Baddabing
"JM Servera" <soyla...@yahoo.es> wrote in message
news:#FzY8k5aCHA.2612@tkmsftngp12...
With your permission, I'll email you private to discuss some of these
issues. Am interested to hear your thoughts.
Baddabing
"JM Servera" <soyla...@yahoo.es> wrote in message
news:#iiLQt6aCHA.1652@tkmsftngp11...
Hi,
Loading, executing, and unloading a simple assembly 500 times gave rise to a
modest increase in memory. I compiled the script below into 500 assemblies,
then ran them with the host code.
Initial footprint was 7,288 k Mem, and 4,460 k Virtual Mem. After looping
500 times, it was 9,396 k and 5,400 respectively. I'll pass this on to the
runtime people.
How many assemblies to do you expect to be loading in real situations? How
often? How big are they?
Peter
--
Peter Torr -- pt...@microsoft.com
This must be the disclaimer I waited years to read:
http://www.microsoft.com/info/cpyright.htm
// ---------- byref.js ----------
import IFace
import System
class Ob extends MarshalByRefObject implements Test
{
function Test()
{
print("My AppDomain is " + AppDomain.CurrentDomain.FriendlyName)
}
}
// ---------- iface.js ----------
package IFace
{
interface Test
{
function Test() : void
}
}
// ---------- host.js ----------
import IFace
import System
import System.Reflection
print("Starting... press a key")
System.Console.ReadLine()
for (var i : int = 1; i <= 500; i++)
{
var ad : AppDomain = AppDomain.CreateDomain("MyDomain" + i)
var ob : Test = ad.CreateInstanceAndUnwrap("byref" + i, "Ob")
ob.Test()
ob = null
AppDomain.Unload(ad)
ad = null
}
var ass : Assembly[] = AppDomain.CurrentDomain.GetAssemblies()
for (var j : int in ass)
print(ass[j])
GC.Collect()
GC.Collect()
GC.Collect()
print("Done... press a key")
System.Console.ReadLine()
Thanks,
JM
"Peter Torr (MS)" <pt...@microsoft.com> escribió en el mensaje
news:uI$c2uAbCHA.1712@tkmsftngp11...
using System;
namespace Test
{
class Class1
{
static int count=0;
public static void loadModule()
{
try
{
string assemblyName=(string)
AppDomain.CurrentDomain.GetData("AssemblyName");
object c=(object) System.Reflection.Assembly.LoadFrom(assemblyName);
Console.WriteLine("{0} loaded in
{1}",assemblyName,AppDomain.CurrentDomain.FriendlyName);
}
catch{}
}
static void SearchDlls(string path)
{
foreach(string s in System.IO.Directory.GetDirectories(path))
{
foreach(string file in System.IO.Directory.GetFiles(s,"*.dll"))
{
AppDomain p=null;
p= AppDomain.CreateDomain("test");
p.SetData("AssemblyName", file);
p.DoCallBack(new CrossAppDomainDelegate(loadModule));
count++;
AppDomain.Unload(p);
}
SearchDlls(s);
}
}
[STAThread]
static void Main(string[] args)
{
string s=System.Environment.GetEnvironmentVariable("ProgramFiles");
System.Reflection.Assembly[] assemblies=
AppDomain.CurrentDomain.GetAssemblies();
for (int i=0; i<assemblies.Length; i++)
{
Console.WriteLine(assemblies[i].FullName);
}
Console.WriteLine("Press <return> to start");
Console.ReadLine();
SearchDlls(String.Format("{0}\\Microsoft.Net\\SDK",s));
Console.WriteLine("Loaded {0} assemblies",count);
assemblies= AppDomain.CurrentDomain.GetAssemblies();
for (int i=0; i<assemblies.Length; i++)
{
Console.WriteLine(assemblies[i].FullName);
}
assemblies= null;
s= null;
GC.Collect();
GC.Collect();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.ReadLine();
}
}
}
"JM Servera" <soyla...@yahoo.es> escribió en el mensaje
news:#iiLQt6aCHA.1652@tkmsftngp11...
I'm still trying to get an answer to this one...
Peter
Thx.
- Rick
"Peter Torr (MS)" <pt...@microsoft.com> wrote in message
news:ulM2qLJcCHA.2112@tkmsftngp09...
Thanks,
Stacey Blaschke
eEye Digital Security
"Peter Torr (MS)" <pt...@microsoft.com> wrote in message
news:ulM2qLJcCHA.2112@tkmsftngp09...
- Steve
"Rick Bullotta" <rickbu...@comcast.net> wrote in message
news:eCTdJ5$sCHA.2124@TK2MSFTNGP12...
Regards,
Viatcheslav V. Vassiliev
"Berkflow" <sbe...@hotmail.com> сообщил/сообщила в новостях следующее:
news:ucQ5URdB...@TK2MSFTNGP11.phx.gbl...
Also check the following article.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/htm
l/csharp05162002.asp
http://www.west-wind.com/presentations/DynamicCode/DynamicCode.htm
Sorry for any word wrap.
using System;
using Microsoft.VisualBasic.Vsa;
using Microsoft.Vsa;
using System.Reflection;
namespace Recycle
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
AppDomain engineDomain = null;
System.IO.StreamWriter writer = null;
try
{
int max = 100;
if(args.Length > 0 )
max = Convert.ToInt32(args[0])+1;
string assemblyName =
Assembly.GetAssembly(typeof(Recycle.ScriptEngine)).FullName;
for(int i = 1; i < max; i++)
{
Console.WriteLine("Instance = "+i.ToString());
engineDomain = AppDomain.CreateDomain("EngineDomain",null,null);
ScriptEngine engine = (ScriptEngine)
engineDomain.CreateInstanceAndUnwrap(assemblyName,"Recycle.ScriptEngine");
engine.Compile();
engine.Close();
AppDomain.Unload(engineDomain);
engineDomain = null;
}
}
catch(System.Exception error)
{
Console.Write(error.ToString());
}
finally
{
if(writer != null)
writer.Close();
writer = null;
}
Console.WriteLine("Press any key to end.");
Console.Read();
}
}
public class ScriptEngine :System.MarshalByRefObject
{
Microsoft.VisualBasic.Vsa.VsaEngine engine;
private string _script;
public ScriptEngine()
{
this._script = "Imports System\n"+
"Public Module script\n"+
"\tSub main\n"+
"\tSystem.Console.WriteLine(\"VSA Engine \")\n"+
"\tEnd Sub\n"+
"End Module";
this.engine = new VsaEngine();
engine.RootMoniker = "Recycle://script";
this.engine.Site = new VsaSiteImpl();
engine.InitNew();
engine.RootNamespace = "Test";
engine.Name = "Test";
engine.GenerateDebugInfo = false;
Microsoft.Vsa.IVsaReferenceItem systemRef=
(Microsoft.Vsa.IVsaReferenceItem)engine.Items.CreateItem("system.dll",Micros
oft.Vsa.VsaItemType.Reference, Microsoft.Vsa.VsaItemFlag.None);
systemRef.AssemblyName = "system.dll";
Microsoft.Vsa.IVsaCodeItem scriptCode=
(Microsoft.Vsa.IVsaCodeItem)engine.Items.CreateItem("main",Microsoft.Vsa.Vsa
ItemType.Code,VsaItemFlag.Module);
scriptCode.SourceText=this._script;
}
public void Close()
{
this.engine.Close();
}
public void Compile()
{
this.engine.Compile();
}
public void Run()
{
if(this.engine.IsCompiled)
{
this.engine.Run();
string strNamespace = engine.RootNamespace;
string FullName = strNamespace +".script";
// Get the method from the type
Type ModType = engine.Assembly.GetType(FullName,true,true);
string main = "main";
System.Reflection.MethodInfo method = ModType.GetMethod(main);
method.Invoke(null,null);
}
}
}
}
public class VsaSiteImpl : Microsoft.Vsa.IVsaSite
{
#region Implementation of IVsaSite
public object GetEventSourceInstance(string itemName, string
eventSourceName)
{
return null;
}
public object GetGlobalInstance(string name)
{
return null;
}
public void Notify(string notify, object info)
{
}
public bool OnCompilerError(Microsoft.Vsa.IVsaError error)
{
Console.Write(error.ToString());
return false;
}
public void GetCompiledState(out byte[] pe, out byte[] debugInfo)
{
pe = null;
debugInfo = null;
}
#endregion}
}
"Viatcheslav V. Vassiliev" <sup...@oledbdirect.com> wrote in message
news:uAW4Cdn...@TK2MSFTNGP12.phx.gbl...
sysProc.StartInfo.FileName = "MyVsaServer.exe";
sysProc.Start();
Type t = Type.GetType("MyVsaServer.WorkItem");
System.Runtime.Remoting.ObjRef or = sysProc.CreateObjRef(t);
IWorkItem wi = (IWorkItem)or.GetRealObject(new
System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.S
treamingContextStates.All));
----------------------------------------------------------------------------
---------------
"Jim Bob" <idont...@msn.ca> wrote in message
news:OR4hB5BC...@TK2MSFTNGP10.phx.gbl...