Полностью согласен с этими тезисами, хотя и не вижу, как они относятся к данной ситуации. Как следовало написать код вместо фрагмента, который тебе так не понравился?
Я понимаю твоё негодование после уймы потраченного времени ;) но по сути здесь нет никаких проблем, кроме предупреждений слишком «умного» компилятора.
Переменная j (индекс аргумента) на практике всегда от 0 до 3.
Заводить где-то отдельную константу BUFFER_SIZE для буфера, который заполняется лишь в той же строке, полагаю, перебор. Boilerplate, ничуть не улучшающий читабельность.
И что же делать с возвращаемым значением? Проверять, что 10 байт хватит на запись трёх символов? А если нет, то что? :) По мне так тоже перебор.
Что не так с форматом? И чем поможет itoa, чтобы напечатать x2?
Я ни в коем случае не хочу оспаривать паттерны написания корректного кода, но в данном конкретном примере сразу понятно, что хотел выразить автор, и что никаких багов с переполнением буфера здесь быть не может. То, что более свежий gcc стал выдавать предупреждение — да, стоит поправить, но делать из этого выводы, что написана какая-то фигня, будет преждевременно.
Во как! Стало быть, в свежей Убунте весь этот путь уже прошли. Тогда, чтобы играться с OpenJDK на Ubuntu, логичней брать исходники не с openjdk.java.net, а с launchpad.net, где все необходимые для компиляции патчи уже сделаны.
В README к сборке OpenJDK указано, какими версиями тулов собирается официальный билд. Там же отмечено, что
Compilation problems with newer or different C/C++ compilers is a common problem.
Понятно, что поддержка новый версий компилятора — большая работа, сопряжённая с риском для уже проверенного кода, и никто не будет её делать для устаревающей JDK 8, поскольку это ни разу не критичная проблема.
Кстати, ещё один хинт: java -Xinternalversion скажет, каким компилятором собиралась данная конкретная версия JDK. Например, для стандартного пакета в Ubuntu это будет gcc 5.4.0. Можно сэкономить кучу времени и нервов, просто выбрав для сборки gcc-5.
$ java -Xinternalversion
OpenJDK 64-Bit Server VM (25.181-b13) for linux-amd64 JRE (1.8.0_181-8u181-b13-0ubuntu0.16.04.1-b13), built on Jul 30 2018 21:06:27 by "buildd" with gcc 5.4.0 20160609
1. В качестве резерва памяти для обработки OOME создаём байтовый массив.
2. Держим на него strong reference и SoftReference.
3. При возникновении OOME обнуляем strong reference; массив станет softly reachable, а, значит, резерв заведомо освободится до возникновения следующего OOME.
нет никакой гарантии, что между очисткой и логированием успеет пройти сборка и мусора.
Либо сборка мусора пройдёт, либо логирование успешно выполнится безо всякой сборки. Аспект многопоточности оставлю в стороне — можно манипулировать размером резерва.
Можно, если воспользоваться SoftReference. И для неё спецификация как раз гарантирует, что ссылка будет очищена до того, как выбросится OutOfMemoryError.
Зря комментарий svr_91 заминусовали. Вполне годное решение, которое встречал в реальных проектах.
Что уж говорить, если даже стандартный пример Java2Demo, скачанный с официального сайта Oracle из раздела JDK 8u172 Demos and Samples, просто не запускается на JDK 10.
Сорри, насчёт "не обязан" погорячился. В спеке чётко прописано, что Java SE 10-совместимая реализация JVM должна поддерживать все .class файлы, начиная с версии 45.
Спасибо, я в курсе, что HotSpot их поддерживает для старых классов (хотя и не обязан). Суть в том, что с API ровно та же история. Его теоретически могут менять в новых версиях, но на практике предусматривают решения для обратной совместимости. В некоторых случаях даже баги оставляют для поддержки предыдущих версий (см. свойства sun.nio.ch.bugLevel и sun.nio.cs.bugLevel).
Точно так же, как и нет гарантий совместимости JVMS 8 и JVMS X. Могут, к примеру, пару байткодов удалить (как уже было с jsr/ret). Гарантии Javadoc в этом смысле не слабее и не сильнее гарантий других спецификаций.
OK, а в чём альтернативность-то? :) Про inconsistent hashing в разборе написано. А assert'ы лишь для того, чтобы показать ограничения на входные данные, не удлиняя сильно условие задачи.
Нужно отметить, что не все из перечисленных методов являются интринсиками в прямом смысле, то есть, вовсе не обязательно, что JIT подставляет вместо вызова особый код. Некоторые компилируются как обычные Java методы, а их упоминание в vmSymbols.hpp обусловлено необходимостью отличить их в рантайме по другой причине.
Например, Method.invoke отмечен, чтобы не учитывать его в security check при обходе стека. Наличие Throwable.fillInStackTrace служит хинтом для Escape Analysys, а Unsafe.park/unpark и вовсе напрасно отмечены.
Да, и ещё то, что с int типом будет уже не важно, создаётся ли StringBuilder() с размером по умолчанию или StringBuilder(metrics) с заранее предопределённым размером. В обоих случаях паттерн new StringBuilder(*).append()...append().toString() скомпилируется как интринсик без вызова Java кода, и производительность Concatenation vs. StringBuilder будет одинаковая, несмотря на различия в байткоде.
Если же в цепочке попадётся append(long), то оптимизация не отработает — ну, не реализовали почему-то в JDK 8), то есть, будет честный вызов Java кода.
За задачи и разбор +1, но делать выводы о производительности по байткоду не совсем корректно, как я показывал в презентации. Замени, например, timestamp с long на int и сравни заново… Довод про конструктор StringBuilder развалился на глазах, правда? И выводы будут уже совсем другие.
В этой же презентации про конкатенацию, кстати, тоже есть. Нельзя бенчмаркать StringBuilder и не упомянуть фичу Хотспота под названием OptimizeStringConcat.
stackoverflow.com/questions/22358071/differences-between-oracle-jdk-and-openjdk
stackoverflow.com/questions/44335605/openjdk-vs-java-hotspotvm
itoa
, чтобы напечататьx2
?Я ни в коем случае не хочу оспаривать паттерны написания корректного кода, но в данном конкретном примере сразу понятно, что хотел выразить автор, и что никаких багов с переполнением буфера здесь быть не может. То, что более свежий gcc стал выдавать предупреждение — да, стоит поправить, но делать из этого выводы, что написана какая-то фигня, будет преждевременно.
Понятно, что поддержка новый версий компилятора — большая работа, сопряжённая с риском для уже проверенного кода, и никто не будет её делать для устаревающей JDK 8, поскольку это ни разу не критичная проблема.
Кстати, ещё один хинт:
java -Xinternalversion
скажет, каким компилятором собиралась данная конкретная версия JDK. Например, для стандартного пакета в Ubuntu это будет gcc 5.4.0. Можно сэкономить кучу времени и нервов, просто выбрав для сборки gcc-5.2. Держим на него strong reference и SoftReference.
3. При возникновении OOME обнуляем strong reference; массив станет softly reachable, а, значит, резерв заведомо освободится до возникновения следующего OOME.
Либо сборка мусора пройдёт, либо логирование успешно выполнится безо всякой сборки. Аспект многопоточности оставлю в стороне — можно манипулировать размером резерва.
SoftReference
. И для неё спецификация как раз гарантирует, что ссылка будет очищена до того, как выброситсяOutOfMemoryError
.Зря комментарий svr_91 заминусовали. Вполне годное решение, которое встречал в реальных проектах.
Что уж говорить, если даже стандартный пример Java2Demo, скачанный с официального сайта Oracle из раздела JDK 8u172 Demos and Samples, просто не запускается на JDK 10.
Сорри, насчёт "не обязан" погорячился. В спеке чётко прописано, что Java SE 10-совместимая реализация JVM должна поддерживать все .class файлы, начиная с версии 45.
JLS, JVMS, Javadoc,… — это части такой спецификации.
habrahabr.ru/company/mailru/blog/321306/#comment_10068620
vmSymbols.hpp
обусловлено необходимостью отличить их в рантайме по другой причине.Например,
Method.invoke
отмечен, чтобы не учитывать его в security check при обходе стека. НаличиеThrowable.fillInStackTrace
служит хинтом для Escape Analysys, аUnsafe.park/unpark
и вовсе напрасно отмечены.Да, и ещё то, что с
int
типом будет уже не важно, создаётся лиStringBuilder()
с размером по умолчанию илиStringBuilder(metrics)
с заранее предопределённым размером. В обоих случаях паттернnew StringBuilder(*).append()...append().toString()
скомпилируется как интринсик без вызова Java кода, и производительность Concatenation vs. StringBuilder будет одинаковая, несмотря на различия в байткоде.Если же в цепочке попадётся
append(long)
, то оптимизация не отработает — ну, не реализовали почему-то в JDK 8), то есть, будет честный вызов Java кода.В этой же презентации про конкатенацию, кстати, тоже есть. Нельзя бенчмаркать StringBuilder и не упомянуть фичу Хотспота под названием OptimizeStringConcat.