2011-11-22 23 views
14

Có phân tích thoát nào được thực hiện bởi trình biên dịch CLR/JIT không? Ví dụ, trong Java nó xuất hiện một biến vòng lặp một đối tượng được phân bổ trong một vòng lặp mà không thoát khỏi vòng lặp được cấp phát trên ngăn xếp chứ không phải là đống (xem Escape analysis in Java).Phân tích thoát trong .NET CLR VM

Để làm rõ, trong ví dụ bên dưới, trình biên dịch có tối ưu hóa việc phân bổ heap của foo vì nó không bao giờ thoát khỏi vòng lặp hay không.

class Foo 
{ 
    int number; 
    Foo(int number) { this.number = number; } 
    public override string ToString() { return number.ToString(); } 
} 

for (int i = 0; i < 10000000; i++) 
{ 
    Foo foo = new Foo(i); 
    Console.WriteLine(foo.ToString()); 
} 
+0

Thông thường, một biến vòng lặp là một loại giá trị, mà được phân bổ trên stack (trong trường hợp của một vòng lặp). –

+0

Tôi có nghĩa là một biến được phân bổ trong vòng lặp. Tôi sẽ cập nhật câu hỏi để làm rõ. – SimonC

+0

Bạn có nghĩa là biến * không? hoặc đối tượng *? (khái niệm rất khác) –

Trả lời

11

Nếu bạn ngụ ý đối tượng (new Foo(i);), thì sự hiểu biết của tôi là không: điều này không bao giờ được phân bổ trên ngăn xếp; tuy nhiên, nó sẽ chết trong thế hệ zero, vì vậy sẽ rất hiệu quả để thu thập. Tôi không biết mọi góc tối và tối của CLI, nhưng tôi không biết bất kỳ trường hợp nào trong C# sẽ dẫn đến loại tham chiếu được quản lý được phân bổ trên ngăn xếp (chẳng hạn như stackalloc không thực sự đếm, và rất cụ thể). Rõ ràng trong C++ bạn có thêm một vài tùy chọn, nhưng sau đó nó không phải là một thể hiện được quản lý.

Điều thú vị là, trên MonoTouch/AOT, có thể được thu thập ngay lập tức, nhưng đó không phải là máy ảo CLI chính (và dành cho một trường hợp rất cụ thể).

Đối với biến - đó sẽ thường được trên stack (và tái sử dụng cho mỗi lần lặp) - nhưng nó có thể không phải. Ví dụ, nếu đây là một "iterator block", thì tất cả các biến cục bộ không bị loại bỏ thực sự là các trường trên máy trạng thái do trình biên dịch tạo ra. Phổ biến hơn, nếu biến được "bắt" (thành một phương thức ẩn danh hoặc biểu thức lambda, cả hai dạng này đều đóng), thì biến được chuyển thành một trường trên ngữ cảnh chụp do biên dịch tạo ra, là riêng biệt trên mỗi vòng lặp lặp lại (từ foo được khai báo bên trong vòng lặp). Điều này có nghĩa là mỗi số là riêng biệt trên heap.

Đối với i (biến vòng lặp) - nếu rằng bị bắt, nó được thậm chí thú vị hơn

  • trong C# 1.2 chụp không tồn tại, nhưng bởi spec vòng lặp biến là kỹ thuật mỗi lần lặp
  • trong C# 2,0-4,0, biến vòng lặp được chia sẻ (gây ra chụp khét tiếng/foreach câu hỏi thường gặp)
  • trong C# 5.0 trở lên biến vòng lặp là mỗi lần lặp lại

này chỉ làm cho một sự khác biệt khi biến được chụp, nhưng thay đổi ngữ nghĩa chính xác cách nó biểu hiện trên chụp bối cảnh

1

Trong khi x86 JIT là giỏi valuetypes 'nội tuyến, đoạn mã của bạn sẽ không được coi là phương pháp ToString sẽ là một cuộc gọi ảo trên một đối tượng đóng hộp. Chỉnh sửa: Đây có thể không phải là trường hợp, vì bạn không ghi đè ToString.

Tuy nhiên, JIT x64 không thực hiện điều này từ thử nghiệm của tôi.

Edit:

Nếu có thể, kiểm tra mã của bạn trên cả x86 và x64.

+1

'Foo' là một lớp mặc dù, vì vậy tôi không chắc chắn bao nhiêu điều này được áp dụng. –

5

Loại giá trị có thể được cấp phát trên ngăn xếp (không phải lúc nào), nhưng điều này cũng không đúng đối với trường hợp loại tham chiếu. Trong thực tế:

Cụ thể, vị trí lưu trữ của các thể hiện loại tham chiếu luôn được coi là mặc dù chúng tồn tại lâu dài, ngay cả khi chúng được chứng minh là có thời gian sống ngắn. Vì vậy, họ luôn luôn đi trên heap.

(Eric Lippert: The Truth About Value Types)

Cũng The Stack Is An Implementation Detail làm cho một đọc tốt.

Các vấn đề liên quan