Según tengo entendido, el código JIT-ed nunca se libera de la memoria mientras se ejecuta el programa. ¿Significa esto que llamar repetidamente a .Compile() en los árboles de expresión pierde memoria?
La implicación de eso sería solo compilar árboles de expresión en constructores estáticos o almacenarlos en caché de alguna otra manera, lo que puede no ser tan simple. ¿Derecha?
Probablemente estén GCed... LambdaExpression.Compile() usa la clase LambdaCompiler.Compile(LambdaExpression, DebugInfoGenerator) , que a través de uno de los constructores de LambdaCompiler usa DynamicMethod que, de MSDN:
Define y representa un método dinámico que se puede compilar, ejecutar y descartar. Los métodos descartados están disponibles para la recolección de basura.
Intenté probar esto generando continuamente árboles de expresión en segundo plano y luego recolectando toda la basura y monitoreando el espacio usado en el subproceso de la GUI.
Parecería que el uso de la memoria se mantiene estable en alrededor de 655000 bytes después de un par de horas. Así que diría que es seguro volverse loco con los árboles de expresión.
Si alguien quiere mi código de prueba hacky, aquí está:
using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Threading; using System.Windows.Forms; namespace Experiments { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Ensuring that always the same amount of memory is used for point storage. bytesUsed = new Queue<long>(1000); var points = chart1.Series[0].Points; for (var i = 0; i < 1000; ++i) { bytesUsed.Enqueue(0); points.Add(0); } thread = new Thread(ThreadMethod); thread.Start(); timer1.Interval = 10000; timer1.Enabled = true; timer1_Tick(null, null); } private readonly Queue<long> bytesUsed; private void timer1_Tick(object sender, EventArgs e) { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); bytesUsed.Dequeue(); bytesUsed.Enqueue(GC.GetTotalMemory(false)); var points = chart1.Series[0].Points; points.Clear(); foreach (var value in bytesUsed) points.Add(value); } private Thread thread; private volatile bool stopping; private void ThreadMethod() { var random = new Random(); while (!stopping) { var constant = Expression.Constant(random.Next(), typeof(int)); var param = Expression.Parameter(typeof(int)); var mul = Expression.Multiply(param, constant); var add = Expression.Multiply(mul, param); var sub = Expression.Subtract(add, constant); var lambda = Expression.Lambda<Func<int, int>>(sub, param); var compiled = lambda.Compile(); } } protected override void Dispose(bool disposing) { stopping = true; if (thread != null && disposing) thread.Join(); if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } } }