2016-02-14 1 views
4

я узнал от this answer на for и while петель в C#, что: «Компилятор/JIT имеет оптимизации для этого сценария до тех пор, пока вы используете arr.Length в Состояние:»Компилятор оптимизации/JIT в допустимых границах проверки для цикла в Java и C++

for(int i = 0 ; i < arr.Length ; i++) { 
    Console.WriteLine(arr[i]); // skips bounds check 
} 

Это искушение меня задаться вопросом, если Java компилятор имеет заточку.

for(int i=0; i<arr.length; i++) { 
    System.out.println(arr[i]); // is bounds check skipped here? 
} 

Я думаю, что да, не так ли? То же самое происходит при использовании Collection, например ArrayList?


Но что, если я должен использовать значение myList.size()внутри тела из цикла, принимая во внимание в настоящее время myList быть ArrayList? Таким образом, в этом случае не будет подъемmyList.size() справка, так как size() - вызов метода? Например, может быть что-то вроде этого:

int len = myList.size(); // hoisting for using inside the loop 
for(int i = 0; i < myList.size(); i++) { // not using hoisted value for optimization 
    System.out.println(myList.get(i)); 

    if(someOtherVariable == len) { 
     doSomethingElse(); 
    } 
} 

Edit: Хотя я не получил ответа на Java, я все еще добавить вторую часть на этот вопрос.

Q: Имеет ли C++ (C++ 98/C++ 11) такие оптимизации, например. для vector.size() и string.size()? Например, что лучше по производительности?

for (int i = 0; i < myvector.size(); ++i) 
    cout << myvector[i] << " "; // is bounds checking skipped here, like in C#? 

или

// does this manual optimisation help improve performance, or does it make? 
int size = myvector.size(); 
for (int i = 0; i < size; ++i) 
    cout << myvector[i] << " "; 

Тем не менее, это такая оптимизация существует для std::string, а?

+5

Не беспокойтесь об этом; вызов метода обычно будет встраиваться в любом случае. – SLaks

+0

@SLaks, пожалуйста, продумайте немного о том, чтобы быть встроенным? –

+3

http://stackoverflow.com/q/1546694/34397 – SLaks

ответ

2

Java

Поскольку Java 7, компилятор исключает проверки границ для примитивных массивов, если он может доказать, что вне связанного доступа не представляется возможным. Перед Java 7 компиляторы JIT или AOT могут это сделать. Для компиляторов JIT и AOT он не ограничен for (int i = 0; i < arr.length; i++), он может перемещать проверки границ вне цикла для циклов, таких как for (int i = 0; i < 10000000; i++), уменьшая его до одной проверки. Если эта проверка завершится с ошибкой, она запустит версию кода с полной проверкой границ, чтобы исключить исключение в правильном месте.

Для коллекций это намного сложнее, потому что границы проверяются вызываемым методом, а не местом вызова. Как правило, он не может быть исключен из байт-кода, но компиляторы JIT и AOT могут устранить его, если они могут встроить методы (которые зависят от того, как создается объект и где он хранится, между прочим, потому что все не частные методы в Java являются виртуальными, поэтому компилятору необходимо убедиться, что ему не понадобится виртуальный вызов), но я не знаю, действительно ли они это делают.

C++

C++ не проверяет границы в operator []. Он проверяет границы, когда вы используете at.at является встроенным, поэтому он зависит от конкретного компилятора и его флагов, но, как правило, компилятор может удалить проверку границ, если он может доказать, что доступ вне границ невозможен. Он также может перемещать проверку границ вне цикла, но он все равно должен гарантировать, что исключение будет выбрано в нужном месте, поэтому я не знаю, будет ли это делать.

Оба примера для C++ будут эквивалентны в компиляторе, который выполняет Dead Code Elimination, если вы не используете int size после цикла for. Последнее может быть быстрее, если вы будете использовать некоторые методы, которые не включены. (Вы также можете поместить определение size внутри инициализации: for (int i = 0, size = myvector.size(); i < size; ++i))