Pregunta

I tiene algo de código # C que está utilizando CSharpCodeProvider.CompileAssemblyFromSource para crear un conjunto en la memoria. Después recogió el montaje se ha de basura, mi aplicación utiliza más memoria que lo hizo antes de la creación de la asamblea. Mi es el código de una aplicación web ASP.NET, pero he duplicado este problema en un WinForm. Estoy usando System.GC.GetTotalMemory (verdadero) y Red Gate memoria ANTS Profiler para medir el crecimiento (alrededor de 600 bytes con el código de ejemplo).

A partir de la búsqueda que he hecho, parece que la fuga proviene de la creación de nuevos tipos, no es realmente de cualquier objeto que estoy que referencie a. Algunas de las páginas web que he encontrado han mencionado algo acerca de dominio de aplicación, pero no entiendo. ¿Puede alguien explicar lo que está pasando aquí y cómo solucionarlo?

A continuación, algunos ejemplos de código de la filtración:

private void leak()
{
    CSharpCodeProvider codeProvider = new CSharpCodeProvider();
    CompilerParameters parameters = new CompilerParameters();
    parameters.GenerateInMemory = true;
    parameters.GenerateExecutable = false;

    parameters.ReferencedAssemblies.Add("system.dll");

    string sourceCode = "using System;\r\n";
    sourceCode += "public class HelloWord {\r\n";
    sourceCode += "  public HelloWord() {\r\n";
    sourceCode += "    Console.WriteLine(\"hello world\");\r\n";
    sourceCode += "  }\r\n";
    sourceCode += "}\r\n";

    CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, sourceCode);
    Assembly assembly = null;
    if (!results.Errors.HasErrors)
    {
        assembly = results.CompiledAssembly;
    }
}

Actualización 1: Esta pregunta puede estar relacionada: dinámicamente la carga y descarga aa generado DLL usando CSharpCodeProvider

Actualización 2: Tratar de entender más dominios de aplicación, he encontrado esto: ¿Qué es un dominio de aplicación - una explicación para principiantes .Net

Actualización 3: Para aclarar, estoy buscando una solución que proporciona la misma funcionalidad que el código anterior (compilación y proporcionar acceso al código generado) sin fugas de memoria. Parece que la solución implicará la creación de un nuevo dominio de aplicación y cálculo de referencias.

¿Fue útil?

Solución

No se admite Descarga de un ensamblaje. Parte de la información acerca de por qué se puede encontrar aquí . Parte de la información sobre el uso de un dominio de aplicación se puede encontrar aquí .

Otros consejos

Creo que tengo una solución de trabajo. Gracias a todos por mí apuntando en la dirección correcta (espero).

Asambleas no puede ser descargada directamente, pero puedo dominios de aplicación. He creado una biblioteca de ayuda que se carga en un nuevo dominio de aplicación y es capaz de compilar un conjunto nuevo de código. Esto es lo que la clase en la que se ve una biblioteca de ayuda como:

public class CompilerRunner : MarshalByRefObject
{
    private Assembly assembly = null;

    public void PrintDomain()
    {
        Console.WriteLine("Object is executing in AppDomain \"{0}\"",
            AppDomain.CurrentDomain.FriendlyName);
    }

    public bool Compile(string code)
    {
        CSharpCodeProvider codeProvider = new CSharpCodeProvider();
        CompilerParameters parameters = new CompilerParameters();
        parameters.GenerateInMemory = true;
        parameters.GenerateExecutable = false;
        parameters.ReferencedAssemblies.Add("system.dll");

        CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);
        if (!results.Errors.HasErrors)
        {
            this.assembly = results.CompiledAssembly;
        }
        else
        {
            this.assembly = null;
        }

        return this.assembly != null;
    }

    public object Run(string typeName, string methodName, object[] args)
    {
        Type type = this.assembly.GetType(typeName);
        return type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, assembly, args);
    }

}

Es muy básico, pero era suficiente para la medición. PrintDomain está allí para comprobar que lo hace vivo en mi nuevo dominio de aplicación. Compilar toma algo de código fuente y trata de crear un ensamblado. Ejecutar permite ejecutar a probar métodos estáticos a partir del código fuente dada.

Así es como yo uso la biblioteca de ayuda:

static void CreateCompileAndRun()
{
    AppDomain domain = AppDomain.CreateDomain("MyDomain");

    CompilerRunner cr = (CompilerRunner)domain.CreateInstanceFromAndUnwrap("CompilerRunner.dll", "AppDomainCompiler.CompilerRunner");            
    cr.Compile("public class Hello { public static string Say() { return \"hello\"; } }");            
    string result = (string)cr.Run("Hello", "Say", new object[0]);

    AppDomain.Unload(domain);
}

Es, básicamente, crea el dominio, se crea una instancia de mi clase de ayuda (CompilerRunner), lo utiliza para compilar una nueva asamblea (oculto), se ejecuta un código de esa nueva asamblea, y luego descarga el dominio para liberar memoria.

Se dará cuenta de la utilización de MarshalByRefObject y CreateInstanceFromAndUnwrap. Estos son importantes para asegurar que la biblioteca de ayuda realmente vivo en el nuevo dominio.

Si alguien da cuenta de cualquier problema o tiene sugerencias para mejorar esto, me encantaría escucharlos.

También puede encontrar esta entrada de blog útil: Uso de dominio de aplicación para cargar y descargar ensamblados dinámicos. proporciona un código de ejemplo que muestra cómo crear un dominio de aplicación, cargar una (dinámica) de montaje en él, hacer algo de trabajo en el nuevo dominio de aplicación y luego descargarlo .

Editar:. Conexión fija como fuera de punta en los comentarios a continuación

¿Se puede esperar hasta .NET 4.0? Con él se puede utilizar árboles de expresión y el DLR para generar dinámicamente código sin el problema de pérdida de memoria de generación.

Otra opción es utilizar .NET 3.5 con un lenguaje dinámico como IronPython.

EDIT: Expresión Ejemplo árbol

http://www.infoq.com/articles/expression-compiler

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top