Trình biên dịch C # không làm thay đổi IL phát ra rất nhiều trong bản dựng Phát hành. Đáng chú ý là nó không còn phát ra các opp NOP cho phép bạn đặt một điểm dừng trên một dấu ngoặc nhọn. Cái lớn nhất là trình tối ưu hóa được tích hợp trong trình biên dịch JIT. Tôi biết nó thực hiện các tối ưu hóa sau:
Phương pháp nội tuyến. Một cuộc gọi phương thức được thay thế bằng cách tiêm mã của phương thức. Đây là một cái lớn, nó làm cho người truy cập tài sản về cơ bản là miễn phí.
Phân bổ thanh ghi CPU. Các biến cục bộ và đối số phương thức có thể được lưu trữ trong một thanh ghi CPU mà không bao giờ (hoặc ít thường xuyên hơn) được lưu trữ trở lại khung ngăn xếp. Đây là một vấn đề lớn, đáng chú ý vì làm cho việc gỡ lỗi mã được tối ưu hóa trở nên khó khăn. Và cho từ khóa dễ bay hơi một ý nghĩa.
Kiểm tra chỉ số mảng loại bỏ. Một tối ưu hóa quan trọng khi làm việc với các mảng (tất cả các lớp bộ sưu tập .NET sử dụng một mảng bên trong). Khi trình biên dịch JIT có thể xác minh rằng một vòng lặp không bao giờ lập chỉ mục một mảng ngoài giới hạn thì nó sẽ loại bỏ kiểm tra chỉ mục. Cái lớn.
Vòng lặp không kiểm soát. Vòng lặp với cơ thể nhỏ được cải thiện bằng cách lặp lại mã lên đến 4 lần trong cơ thể và lặp ít hơn. Giảm chi phí chi nhánh và cải thiện các tùy chọn thực thi siêu vô hướng của bộ xử lý.
Loại bỏ mã chết. Một câu lệnh như if (false) {/ ... /} bị loại bỏ hoàn toàn. Điều này có thể xảy ra do liên tục gấp và nội tuyến. Các trường hợp khác là nơi trình biên dịch JIT có thể xác định rằng mã không có tác dụng phụ có thể xảy ra. Tối ưu hóa này là những gì làm cho mã hồ sơ rất khó khăn.
Mã nâng hàng. Mã bên trong một vòng lặp không bị ảnh hưởng bởi vòng lặp có thể được chuyển ra khỏi vòng lặp. Trình tối ưu hóa của trình biên dịch C sẽ dành nhiều thời gian hơn cho việc tìm kiếm cơ hội để nâng hàng. Tuy nhiên, đó là một tối ưu hóa đắt tiền do phân tích luồng dữ liệu cần thiết và jitter không thể dành thời gian nên chỉ có các trường hợp rõ ràng. Buộc các lập trình viên .NET phải viết mã nguồn tốt hơn và tự nâng lên.
Loại bỏ biểu thức phụ phổ biến. x = y + 4; z = y + 4; trở thành z = x; Khá phổ biến trong các câu lệnh như Dest [ix + 1] = src [ix + 1]; được viết để dễ đọc mà không giới thiệu một biến trợ giúp. Không cần phải thỏa hiệp khả năng đọc.
Gấp liên tục. x = 1 + 2; trở thành x = 3; Ví dụ đơn giản này được trình biên dịch bắt gặp sớm, nhưng xảy ra vào thời điểm JIT khi các tối ưu hóa khác làm cho điều này có thể.
Sao chép tuyên truyền. x = a; y = x; trở thành y = a; Điều này giúp người cấp phát đăng ký đưa ra quyết định tốt hơn. Nó là một vấn đề lớn trong jitter x86 vì nó có ít thanh ghi để làm việc. Có nó chọn đúng là rất quan trọng để hoàn thiện.
Đây là những tối ưu hóa rất quan trọng có thể tạo ra sự khác biệt lớn khi, ví dụ, bạn cấu hình bản dựng Debug của ứng dụng của bạn và so sánh nó với bản dựng Phát hành. Điều đó chỉ thực sự quan trọng mặc dù khi mã nằm trên đường dẫn quan trọng của bạn, 5 đến 10% mã bạn viết thực sự ảnh hưởng đến sự hoàn hảo của chương trình của bạn. Trình tối ưu hóa JIT không đủ thông minh để biết trước điều gì là quan trọng, nó chỉ có thể áp dụng quay số "biến nó thành mười một" cho tất cả các mã.
Kết quả hiệu quả của những tối ưu hóa này trong thời gian thực hiện chương trình của bạn thường bị ảnh hưởng bởi mã chạy ở nơi khác. Đọc tệp, thực hiện truy vấn dbase, v.v. Làm cho công việc trình tối ưu hóa JIT hoàn toàn vô hình. Nó không phiền đâu :)
Trình tối ưu hóa JIT là mã khá đáng tin cậy, chủ yếu là do nó đã được đưa vào thử nghiệm hàng triệu lần. Rất hiếm khi gặp sự cố trong phiên bản xây dựng Phiên bản của chương trình của bạn. Nó không xảy ra tuy nhiên. Cả jitter x64 và x86 đều gặp vấn đề với cấu trúc. Jitter x86 gặp rắc rối với tính nhất quán của dấu phẩy động, tạo ra các kết quả khác nhau một cách tinh tế khi các trung gian của phép tính dấu phẩy động được giữ trong một thanh ghi FPU với độ chính xác 80 bit thay vì bị cắt bớt khi bị xóa vào bộ nhớ.