Я пытаюсь получить как можно больше производительности от какого-то внутреннего метода.
Java-код:
List<DirectoryTaxonomyWriter> writers = Lists.newArrayList();
private final int taxos = 4;
[...]
@Override
public int getParent(final int globalOrdinal) throws IOException {
final int bin = globalOrdinal % this.taxos;
final int ordinalInBin = globalOrdinal / this.taxos;
return this.writers.get(bin).getParent(ordinalInBin) * this.taxos + bin; //global parent
}
В своем профилировщике я увидел, что процессор загружается на 1% java.util.Objects.requireNonNull
, но я даже этого не называю. При проверке байт-кода я увидел это:
public getParent(I)I throws java/io/IOException
L0
LINENUMBER 70 L0
ILOAD 1
ALOAD 0
INVOKESTATIC java/util/Objects.requireNonNull (Ljava/lang/Object;)Ljava/lang/Object;
POP
BIPUSH 8
IREM
ISTORE 2
Таким образом, компилятор генерирует эту (бесполезную?) Проверку. Я работаю с примитивами, которые не могут быть в null
любом случае, так почему компилятор генерирует эту строку? Это ошибка? Или «нормальное» поведение?
(Я могу обойтись с битовой маской, но мне просто любопытно)
[ОБНОВИТЬ]
Оператор, похоже, не имеет к этому никакого отношения (см. Ответ ниже)
Используя компилятор eclipse (версия 4.10), я получаю более разумный результат:
public getParent (I) Я бросаю Java / IO / IOException L0 ЛИНИУМЕР 77 L0 ILOAD 1 ICONST_4 IREM ISTORE 2 L1 ЛЕНЕНУМЕР 78 Л
Так что это более логично.
INVOKESTATIC
javac
не генерирует это.openjdk version "11.0.6" 2020-01-14
на Ubuntu 64 бит.Ответы:
Почему бы нет?
Если предположить,
вызов типа
c.test()
гдеc
объявлено какC
должен бросить когдаc
естьnull
. Ваш метод эквивалентентак как вы работаете только с константами. С
test
не статичным, проверка должна быть сделана. Обычно это делается неявно, когда к полю обращаются или когда вызывается нестатический метод, но вы этого не делаете. Так что нужна явная проверка. Одна возможность - позвонитьObjects.requireNonNull
.Байт-код
Не забывайте, что байт-код в основном не имеет отношения к производительности. Задача
javac
состоит в том, чтобы создать некоторый байт-код, выполнение которого соответствует вашему исходному коду. Он не предназначен для какой-либо оптимизации, поскольку оптимизированный код обычно длиннее и сложнее анализировать, в то время как байт-код фактически является исходным кодом для оптимизирующего JIT-компилятора. Так что,javac
как ожидается, будет проще ...Производительность
Я бы сначала обвинил профилировщика. Профилирование Java довольно сложно, и вы никогда не можете ожидать идеальных результатов.
Возможно, вам следует попробовать сделать метод статичным. Вы обязательно должны прочитать эту статью о нулевых проверках .
источник
this
является ли тест нестатичнымnull
. Как вы сказали сами, вызов likec.test()
должен завершиться с ошибкой, когда онc
есть,null
и он должен немедленно завершиться с ошибкой, вместо того, чтобы войти в метод. Так что внутриtest()
,this
никогда не может бытьnull
(иначе была бы ошибка JVM). Так что проверять не нужно. Фактическим исправлением должно быть изменение поляtaxos
наstatic
, так как нет смысла резервировать память в каждом случае для константы времени компиляции. Тогда не имеет значения ,test()
является ли этоstatic
.Что ж, похоже, мой вопрос был «неправильным», поскольку он не имеет ничего общего с оператором, а скорее с самим полем. Все еще не знаю почему ..
Который превращается в:
источник
this
ссылокnull
? Будет ли это возможно?Integer
, а это результат автобокса?ALOAD 0
ссылаетсяthis
? Так что будет иметь смысл (не совсем), что компилятор добавляет проверку нуляthis
? Отлично: /javac
чтобы проверить его завтра; и если это также показывает это поведение, я думаю, что это может быть ошибка javac?Во-первых, вот минимальный воспроизводимый пример такого поведения:
Такое поведение объясняется тем, как компилятор Java оптимизирует константы времени компиляции .
Обратите внимание, что в байт-коде
foo()
нет ссылки на объект, чтобы получить значениеbar
. Это потому, что это константа времени компиляции, и поэтому JVM может просто выполнитьiconst_5
операцию, чтобы вернуть это значение.При переходе
bar
к некомпилируемой постоянной времени (либо путем удаленияfinal
ключевого слова, либо без инициализации в объявлении, но внутри конструктора) вы получите:где
aload_0
толкает ссылку наthis
стек Операнд затем получитьbar
поле этого объекта.Здесь компилятор достаточно умен, чтобы заметить, что
aload_0
(this
ссылка в случае функций-членов) логически не может бытьnull
.Теперь в вашем случае фактически отсутствует оптимизация компилятора?
Смотрите ответ @maaartinus.
источник