编译的表达式树会泄露吗?

16
在我的理解中,即时编译的代码在程序运行时不会被释放出内存。这是否意味着反复调用表达式树的.Compile()会导致内存泄漏?
这意味着只在静态构造函数中编译表达式树或以其他方式缓存它们,可能并不简单。对吧?

你为什么要反复编译相同的表达式?可以提供一些代码示例吗? - Evk
2
为什么假设.Compile()在同一个表达式树上? - Jeroen van Langen
2
@Evk 因为有时候你不会将它们缓存到 Dictionary<> 或静态变量中... 这是一个有趣的问题。 - xanatos
我没有代码示例,也不认为有必要。问题是编译表达式树是否会不可逆地占用一些内存。这意味着开发人员需要注意,在用户在文本框中输入内容时每次生成和编译新树。 - relatively_random
2个回答

15

所以编译后的表达式不会被GC回收吗?看起来好像只有被丢弃的表达式被GC回收了。 - Patrick Hofman
@PatrickHofman 这恰恰相反...它们垃圾回收了...对于“被丢弃”,我认为他们的意思是“不再被引用”。没有任何“Discard()”方法,因此对描述的任何其他解读都是毫无意义的。 - xanatos

12

我尝试通过在后台持续生成表达式树,然后收集所有垃圾并监视GUI线程中使用的空间来进行测试。

几个小时后,内存使用量似乎稳定在大约655000字节左右。因此,我可以说放心地使用表达式树。

表达式树内存使用情况

如果有人想要我的hacky测试代码,这里是:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接