2017-03-27 16 views
11

Theo hiểu biết của tôi, mã JIT-ed không bao giờ được giải phóng khỏi bộ nhớ trong khi chương trình đang chạy. Điều này có nghĩa là việc liên tục gọi số .Compile() trên cây biểu lộ sẽ rò rỉ bộ nhớ?Cây biểu hiện biên dịch có bị rò rỉ không?

Ý nghĩa của việc đó là chỉ biên dịch các cây biểu thức trong các nhà xây dựng tĩnh hoặc lưu chúng theo một cách khác, có thể không đơn giản như vậy. Đúng?

+0

Tại sao bạn sẽ liên tục lập các biểu hiện giống nhau không? Có thể cung cấp một số ví dụ mã? – Evk

+2

Tại sao giả sử '.Compile()' là trên cùng một cây biểu thức? –

+1

@Evk Bởi vì đôi khi bạn không lưu chúng trong một từ điển 'Dictionary <>', hoặc trong một biến tĩnh ... Đây là một câu hỏi thú vị. – xanatos

Trả lời

9

Họ có lẽ GCed ... LambdaExpression.Compile() sử dụng lớp LambdaCompiler.Compile(LambdaExpression, DebugInfoGenerator), mà through one of the LambdaCompiler constructors sử dụng DynamicMethod rằng, từ MSDN:

Định nghĩa và đại diện cho một phương pháp năng động có thể được biên dịch, thực hiện, và bỏ đi. Các phương pháp hủy có sẵn để thu gom rác thải.

+0

Vậy các biểu thức được biên dịch không phải là GC'ed? Nó đọc như chỉ loại bỏ các biểu thức được GC'ed. –

+0

@PatrickHofman Nó là đối diện ... Họ ** là ** GCed ... Đối với "dicarded" Tôi nghĩ rằng họ có nghĩa là "không còn tham chiếu". Không có phương thức "Loại bỏ()" ở bất kỳ đâu, vì vậy bất kỳ cách đọc nào khác của mô tả sẽ là vô nghĩa. – xanatos

4

Tôi đã thử nghiệm điều này bằng cách liên tục tạo ra một cây biểu thức trong nền sau đó thu thập tất cả rác và theo dõi không gian đã sử dụng trong luồng GUI.

Dường như việc sử dụng bộ nhớ vẫn ổn định ở khoảng 655.000 byte sau một vài giờ. Vì vậy, tôi muốn nói rằng nó an toàn để đi hoang dã với cây biểu hiện.

Expression tree memory usage

Nếu bất cứ ai muốn mã kiểm tra hacky của tôi, ở đây nó là:

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); 
     } 
    } 
} 
Các vấn đề liên quan