2014-10-17 20 views
7

Hãy xem xét đoạn mã sau Java:Trình biên dịch Java có tối ưu hóa String.length() trong điều kiện của vòng lặp không?

String buffer = "..."; 
for (int i = 0; i < buffer.length(); i++) 
{ 
    System.out.println(buffer.charAt(i)); 
} 

Kể từ String là bất biến và buffer không được bố trí bên trong vòng lặp, trình biên dịch Java sẽ đủ thông minh để tối ưu hóa đi các cuộc gọi buffer.length() trong cho điều kiện vòng lặp không? Ví dụ, nó sẽ phát ra mã byte tương đương với mã sau đây, trong đó buffer.length() được gán cho một biến, và biến đó được sử dụng trong điều kiện vòng lặp? Tôi đã đọc rằng một số ngôn ngữ như C# làm loại tối ưu hóa này.

String buffer = "..."; 
int length = buffer.length(); 
for (int i = 0; i < length; i++) 
{ 
    System.out.println(buffer.charAt(i)); 
} 

Trả lời

6

Trong Java (và trong .Net), chuỗi được tính dài (số điểm mã UTF-16), do đó, tìm độ dài là thao tác đơn giản.

Trình biên dịch (javac) có thể hoặc không thể thực hiện hoisting, nhưng JVM JIT Compiler sẽ almost certainly nội tuyến cuộc gọi đến .length(), làm buffer.length() gì khác hơn là truy cập bộ nhớ.

+0

Điều gì về các chuỗi dài thực sự, giả sử một vài 1000K? – Drejc

+0

"jitter" là gì? – stackoverflowuser2010

+0

Đó là chi phí 'O (1)', vì vậy nó không quan trọng.Chuỗi được lưu trữ dưới dạng '{length = 1000, dữ liệu ký tự = {0x65, ... 0x65}}'. – Mitch

1

Trình biên dịch Java (javac) không thực hiện tối ưu hóa như vậy. Trình biên dịch JIT có khả năng sẽ tuân theo phương thức length(), mà ít nhất nó sẽ tránh được chi phí của một cuộc gọi phương thức.

Tùy thuộc vào JDK bạn đang chạy, phương thức length() có thể trả về trường cuối cùng là length, đây là truy cập bộ nhớ giá rẻ hoặc độ dài mảng nội bộ của chuỗi char[]. Trong trường hợp thứ hai, chiều dài của mảng là không đổi và tham chiếu mảng có lẽ là final, do đó JIT có thể đủ tinh vi để ghi lại độ dài một lần trong thời gian tạm thời như bạn đề xuất. Tuy nhiên, loại điều đó là một chi tiết thực hiện. Trừ khi bạn kiểm soát mọi máy mà mã của bạn sẽ chạy, bạn không nên tạo quá nhiều giả định về JVM mà nó sẽ chạy, hoặc nó sẽ thực hiện tối ưu hóa gì.

Để biết cách viết mã, gọi trực tiếp số length() trong điều kiện vòng lặp là mẫu mã phổ biến và lợi ích từ khả năng đọc. Tôi muốn giữ cho mọi thứ đơn giản và cho phép trình tối ưu hóa JIT thực hiện công việc của mình, trừ khi bạn đang ở trong một đường dẫn mã quan trọng đã chứng minh các vấn đề về hiệu năng và bạn cũng chứng minh rằng việc tối ưu hóa vi mô là đáng giá.

+0

"Trình biên dịch JIT sẽ có khả năng nội tuyến theo phương thức length()". Bất kỳ tài liệu nào về điều này? Tôi thích đọc về những thứ này. – stackoverflowuser2010

+1

Nó thực sự không trả về độ dài của 'char []', vì 'Chuỗi' chỉ có thể sử dụng một phần của nó. 'String' có trường 'cuối cùng int' của riêng nó để ghi nhớ độ dài. – resueman

+0

Theo mặc định, tôi tin rằng Oracle JVM sẽ nội tuyến tối đa 35 ** byte ** bytecode cho một phương thức đã được gọi ít nhất một lần. Tôi tin rằng có một ngưỡng lớn hơn cho các phương pháp thường được gọi. Bạn có thể kiểm tra [câu hỏi StackOverflow này] (http://stackoverflow.com/questions/18737774/hotspot-jit-inlining-strategy-top-down-or-down-top). @resueman, phiên bản nguồn mà tôi đang xem không có trường riêng biệt. Tuy nhiên, một ví dụ khác về các giả định mà chúng ta không nên thực hiện về JVM/JDK của máy khách :). –

1

Bạn có thể thực hiện một số việc để kiểm tra hai biến thể triển khai của mình.

  1. (khó khăn: dễ dàng) Thực hiện kiểm tra và đo tốc độ trong các điều kiện tương tự cho từng phiên bản của mã. Hãy chắc chắn rằng bạn vòng lặp là đủ quan trọng để nhận thấy một sự khác biệt, có thể là không có.

  2. (khó: trung bình) Kiểm tra mã byte bằng javap và xem cách trình biên dịch dịch cả hai phiên bản (điều này có thể khác nhau tùy thuộc vào việc triển khai javac) hoặc có thể không (khi hành vi được chỉ định trong thông số và không có phòng) để giải thích bởi người thực hiện).

  3. (khó khăn: khó) Kiểm tra đầu ra JIT của cả hai phiên bản với JITWatch, bạn sẽ cần phải có hiểu biết rất tốt về bytecode và assembler.

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