Как избежать кода операции getfield

В классе String Java метод trim содержит следующее:

int off = offset;      /* avoid getfield opcode */
char[] val = value;    /* avoid getfield opcode */

Я немного озадачен комментарием "не использовать код операции getfield"...

Что это значит? (Я так понимаю, это позволяет избежать использования getfield в байт-коде, но почему это хорошо [TM]?)

Это для предотвращения создания объекта в случае, если trim ничего не делает (и, следовательно, возвращается this) или?


person SyntaxT3rr0r    schedule 21.01.2011    source источник


Ответы (2)


Моя предполагаю состоит в том, чтобы скопировать значения в локальные переменные один раз, чтобы избежать многократного извлечения значения поля из кучи для каждой итерации цикла в следующих нескольких строках.

Конечно, возникает вопрос, почему тот же самый комментарий не был применен к локальной переменной «len». (Я также ожидаю, что JIT в любом случае избежит повторной загрузки, тем более что переменные являются окончательными.)

person Jon Skeet    schedule 21.01.2011
comment
Комментарий не относится к 'len', потому что len активно модифицируется в методе, поэтому в любом случае это должна быть локальная переменная. 'off' и 'val', с другой стороны, не изменяются, а существуют исключительно для оптимизации. - person Lars; 21.01.2011
comment
@Lars: хорошо замечено; Я не видел изменения в len. - person Jon Skeet; 21.01.2011
comment
@JonSkeet Если бы вы лично писали эту библиотеку, ожидали ли вы, что сделали бы это? Или просто полагались на JIT для микрооптимизации? - person corsiKa; 28.02.2012
comment
@corsiKa: я бы сначала написал самый простой код, а затем профилировал его. Если бы это предполагало микрооптимизацию, я мог бы применить ее. - person Jon Skeet; 28.02.2012

getfield используется для получения переменной-члена класса.

Как видно из оставшегося кода:

while ((st < len) && (val[off + st] <= ' ')) {
    st++;
}
while ((st < len) && (val[off + len - 1] <= ' ')) {
    len--;
}

Поэтому, когда вы находитесь в цикле, он должен выполнять getfield каждый раз, когда вы ссылаетесь на value или offset. Вы можете столкнуться с большим падением производительности, если цикл выполняется в течение длительного времени (поскольку каждый раз, когда проверяется условие цикла, getfield выполняется как для offset, так и для value). Таким образом, используя локальные переменные off и val, вы уменьшаете влияние на производительность.

person Vivin Paliath    schedule 21.01.2011
comment
Согласен, за исключением того, что это действительно только для неоптимизированного кода. Когда в дело вмешивается JIT, это уже не имеет значения. JIT выполняет оптимизацию, вероятно, помещая значение в регистр; это тривиально разрешено, поскольку оно полностью эквивалентно. Поскольку значение является окончательным, это очевидно. Но можно и без него. - person maaartinus; 21.01.2011
comment
JIT может оптимизировать это. Например, не ждите такой оптимизации от Dalvik. Перетаскивание поля в локальный может быть полезным по другим причинам, например, для проверки значения null для поля, к которому можно получить доступ одновременно. - person NateS; 22.11.2012