2012-02-02 17 views
7

Vì vậy, trong C#, bạn có thể có đoạn mã sau:Tại sao C# ràng buộc các biến cục bộ lên phía trước?

void DoSomething() 
{ 
    //some code. 
    int x = 5; 
    //some more code. 
} 

Ngay sau khi bạn nhập DoSomething, CLR thiết lập không gian cho int x. Tại sao nó không chờ đợi cho đến khi nó đạt đến dòng với int x = 5 trên nó? Đặc biệt là kể từ khi x bị ràng buộc, nó không cho phép bạn thực sự sử dụng nó cho đến khi dòng đó đạt được không?

+8

Tại sao điều chỉnh kích thước ngăn xếp tăng lên bất kỳ tốt hơn so với đặt trước tất cả? – ildjarn

+0

có lẽ, phải mất một thời gian để lộn xộn với ngăn xếp ... nếu tôi có nhiều biến cục bộ, tại sao phải đợi chúng khi tôi không phải (chưa)? – GWLlosa

+2

Phải, phải mất một thời gian để lộn xộn với chồng, do đó, làm tất cả lên phía trước thay vì hơn và hơn mỗi khi một biến mới đi vào phạm vi là chính xác những gì được thực hiện. – ildjarn

Trả lời

13

Ngay khi bạn nhập DoSomething, CLR thiết lập dung lượng cho int x. Tại sao nó không chờ đợi cho đến khi nó đạt đến dòng với int x = 5 trên nó?

Câu hỏi không phải là câu trả lời vì toàn bộ câu hỏi được thiết lập trên tiền đề không chính xác. Không gian lưu trữ cho các biến cục bộ có thể là:

  • phân bổ khi phương pháp này là lần đầu tiên bước vào
  • phân bổ khi kiểm soát đạt đến khai
  • phân bổ khi kiểm soát đạt đến khởi tạo (giả định khởi và tuyên bố là khác nhau)
  • được phân bổ trong các trường hợp đặc biệt - ví dụ: địa phương là địa phương đóng cửa của một lambda hoặc trong khối lặp, hoặc trong khối không đồng bộ, cách thức và thời gian lưu trữ cục bộ được phân bổ có thể phức tạp
  • hoàn toàn; nếu địa phương không bao giờ được sử dụng thì nó có thể không được phân bổ ở nơi đầu tiên.

Các biên dịch C# và trình biên dịch JIT chắc chắn đảm bảo rằng việc lưu trữ địa phương được phân bổ một cách đó là đúng, và cố gắng để đảm bảo rằng nó là hiệu quả. Làm thế nào họ chọn để làm như vậy phụ thuộc vào tình hình chính xác. Nó có thể hiệu quả hơn để phân bổ không gian lên phía trước, và nó có thể là hiệu quả hơn để phân bổ nó chỉ miễn là biến được sử dụng; jitter được phép sử dụng rộng rãi trong việc chọn tuổi thọ của một biến cục bộ. Các biến cục bộ được phép tồn tại lâu hơn và ngắn hơn phạm vi của chúng sẽ ngụ ý nếu jitter có thể làm như vậy mà không vi phạm chính xác chương trình.

Vì tiền đề của câu hỏi không chính xác nên không có câu trả lời cho câu hỏi. Đặt một câu hỏi hay hơn.

+0

Câu trả lời là [mu] (http://bit.ly/s4jx85). – jason

+1

10 upvotes và chấp nhận cho một câu trả lời mà tuyên bố không có câu trả lời cho câu hỏi. Câu trả lời này dường như mâu thuẫn với chính nó. –

+2

@IgbyLargeman: Các gợi ý bạn nhận được khi bạn di chuột qua upvote là "câu trả lời này là hữu ích", không "câu trả lời này trả lời câu hỏi đã được hỏi". Nếu chỉ ra rằng một câu hỏi được xác định trên một tiền đề không chính xác là * hữu ích * thì không có mâu thuẫn ở đó. –

10

Như bạn đã biết, có một số bước từ mã C# để mã nguồn gốc đó là:

  • Biên dịch từ C# để IL (bytecode)
  • JITting từ bytecode để mã gốc

C# không có bất kỳ sự kiểm soát nào về thời gian khi bộ nhớ được cấp phát, những gì bạn gọi là ràng buộc, điều này hoàn toàn phụ thuộc vào JIT. Nhận được điều này ra khỏi con đường của chúng ta hãy xem những gì trong kiểm soát của C#. Mã byte do C# tạo ra phải tuân theo tiêu chuẩn CLR ECMA. Nếu chúng ta đi đến phần 12.1.6.1 của phân vùng 1, chúng ta sẽ thấy rằng tiêu chuẩn xác định rằng nhà của biến cục bộ là trong tiêu đề phương thức. Vì chữ ký của phương thức như quy tắc có xu hướng hiển thị ở đầu phương thức trong danh sách, bạn nhận được một hiển thị (sai) rằng chúng là bị ràng buộc trả trước, trong thực tế có thể có hoặc không có thể xảy ra.

Nếu bạn đang xem mã nguồn gốc được biên dịch, kết quả có thể thay đổi từ nền tảng này sang nền tảng khác. Việc phân bổ không gian lịch sử trên ngăn xếp CPU cho một biến cục bộ được thực hiện bằng một lệnh CPU duy nhất để thay đổi con trỏ ngăn xếp. Nếu bạn muốn biến nó theo biến thì bạn sẽ có nhiều hướng dẫn, một biến cho mỗi biến, ít hiệu quả hơn. Đây là lý do tại sao, ít nhất là trên x86 bạn sẽ thấy rằng không gian trên ngăn xếp CPU được phân bổ trả trước.

1

Câu hỏi của bạn dường như dựa trên một vài giả định:

  • Chi phí thiết lập luôn sẽ cao
  • cài đặt được chỉ xảy ra một số ít lần
  • Tham chiếu/loại giá trị ở cấp CLR luôn có một ánh xạ một với biến ở cấp C#

Điều này có thể đúng với mã của bạn nhưng có thể không đúng đối với phần lớn mã.

Giả định cũng dường như bỏ qua sự hiện diện của các lớp cơ bản của quá trình biên dịch/giải thích điều này xuống mã máy.

Tóm lại, mã bạn viết trong C# là một trừu tượng dựa trên IL là một trừu tượng khác dựa trên CLR, đó là một trừu tượng khác và vân vân.

Đối với những gì đáng giá, tôi có những nghi ngờ nghiêm trọng về quyết định này có ảnh hưởng đáng kể đến hiệu suất của ứng dụng ... nhưng có thể giống như Eric Lippert (http://blogs.msdn.com/b/ericlippert/) có thể chia sẻ phân tích chuyên sâu hơn.

3

trình biên dịch nên làm gì nếu nó tìm thấy một cái gì đó tương tự như:

for (int i = 0; i < 1000; i++) 
{ 
    int j = .... //should the compiler set up space when it reaches this line? 1000 times? 
} 

Bên cạnh đó tôi thực sự nghĩ rằng chi phí thiết lập không gian của người dân địa phương không phải là một yếu tố. Nếu nó được sau đó bạn có thể đối phó với cách quá nhiều người dân địa phương trong một phương pháp duy nhất và bạn tốt hơn off refactoring mã của bạn.

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