Les arbres d'expression compilés fuient-ils?

.net c# expression expression-trees memory-leaks

Question

À ma connaissance, le code JIT-ed n'est jamais libéré de la mémoire pendant l'exécution du programme. Cela signifie-t-il que l'appel répété de .Compile() sur des arbres d'expression .Compile() mémoire?

Cela impliquerait de ne compiler que des arbres d'expression dans des constructeurs statiques ou de les mettre en cache d'une autre manière, ce qui peut ne pas être aussi simple. Droite?

Réponse acceptée

Ils sont probablement GCed ... LambdaExpression.Compile() utilise le LambdaCompiler.Compile(LambdaExpression, DebugInfoGenerator) classe, que par l' un des DynamicMethod LambdaCompiler constructeurs utilise DynamicMethod qui, à partir de MSDN:

Définit et représente une méthode dynamique pouvant être compilée, exécutée et ignorée. Les méthodes rejetées sont disponibles pour la récupération de place.


Réponse populaire

J'ai essayé de tester cela en générant en permanence des arbres d'expression en arrière-plan, puis en collectant tous les déchets et en surveillant l'espace utilisé dans le thread d'interface graphique.

Il semblerait que l’utilisation de la mémoire reste stable aux alentours de 655 000 octets après quelques heures. Donc, je dirais qu'il est prudent de se déchaîner avec des arbres d'expression.

Utilisation de la mémoire par l'arbre d'expression

Si quelqu'un veut mon code de test hacky, le voici:

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);
        }
    }
}


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi