@hirthwork

Тег java в блоге hirthwork

hirthwork

Появилась задача: иметь тредпул, в котором задачи можно прерывать по истечении некоторого таймаута.
Вся гуглёжка сводится к "нет, так нельзя".
Ну мы же инженеры, пьём трипл ипу из черепов фронтендеров, так что откопали, что если в джава послать треду SIGBUS, то он выбросит java.lang.InternalError, который успешно пролетит весь стек вызовов, пока ты его не поймаешь.

Скоро сказка сказывается, да не скоро код пишется.
Прерываемый тред ощущает последствия сигнала иногда за 700мс, а иногда и за несколько секунд (текущий рекорд — 111 секунд).
А если пустить это тестироваться в бесконечном цикле, то итераций через 50 случается SIGABRT. В общем, я уже даже jdk в дебаге собрал и принтфов там наделал, но до конца механику пиздеца пока не понял.

hirthwork

Сегодняшний плюс в карму получают авторы документации по сборке OpenJDK. Первым абзацем всегда должен быть tl;dr: https://github.com/openjdk/...ster/doc/building.md
Это вообще надо законодательно закрепить

hirthwork

Восемь лет на джаве пишу. Сегодня первый раз в жизни получил от компилятора ошибку «illegal forward reference». Век живи — век компилируй

hirthwork

Кр. — сес. тал.

        // g:h       g:h
        test("g:h")
            .s("g").o("h").z()
            .rslv(base).s("g").o("h").z();

А я-то комментарии в коде юнит-тестов пишу. Иногда даже в логгер пишу сообщения, о том, что такая-то часть теста пройдена успешно.
А надо как разработчики Оракла — простенько и со вкусом

hirthwork

В июле в re2j добавили поддержку именованных групп. Я решил протестить его на тех же данных, что в #zhxde. В этот раз с более точным замером времени. Вот результаты:
Для файла размером 1128824 байт:

jni + pcre              — 111ms
com.google.re2j.Pattern — 201ms
java.regex.Pattern      — 886ms

Для файла размером 408739 байт:

jni + pcre              — 13ms
com.google.re2j.Pattern — 40ms
java.regex.Pattern      — 6ms

Какие выводы можно сделать?
1. re2j заявляет что работает с линейной сложностью и это, похоже, примерно выполняется
2. re2j не является серебряной пулей. Т.е. есть случаи, когда java.regex.Pattern его сильно обгоняет
3. Я хуею от результатов java.regex.Pattern. Вот блядь вообще не знаю как объяснить эти результаты. Тем более что регулярка у меня не вот прям сложная, а проверяет, что семь слов встречаются в тексте, а между ними может идти всё что угодно (ну и регистр некоторых символов может варьироваться)
4. jni + pcre неожиданно хорош. С учётом того, что ему нужно сначала целиком скопировать содержимое UTF-16 строки, затем сконвертировать её в UTF-8, а потом прогнать регулярку — это очень неплохой результат.

hirthwork

По результатам работы профайлера 53.86% времени работы программы занимает java.lang.String.charAt(int)

hirthwork

Есть в JNI функция GestStringUTFChars
Так вот, спустя несколько лет использования выяснилось, что она возвращает не UTF-8, а “modified UTF-8” ...или сказка о том как Х-ворк багу при передаче емодзи искал

hirthwork

Решил Х-ворк поддержку IDN в java.net.URI добавить.
Итого найдено две баги в java.net.URI и не понятно вообще как этим говном пользоваться можно.

hirthwork

Есть такой класс в Java NIO: java.net.SocketChannel
Для удобства олдфагов у него есть метод Socket socket();
Соответственно олдфаги могут делать channel.socket().getInputStream() и channel.socket().getOutputStream() и пердолиться в массивчики вместо того, чтобы читать документацию по непонятному ByteBuffer.
Недоверчивые олдфаги естественно сначала написали тест где сделали channel.socket().getInputStream().read() и убедились, что он кидает эксепшен по таймауту.
Ваш покорный слуга и слишком доверчивый олдфаг сегодня в продакшене узнал, что channel.socket().getOutputStream().write(buf) таймаута по эксепшену не кидает.
Не используйте Джаву. Оставьте это мне. Через страдания я приду к искуплению.

hirthwork


Took me a while

hirthwork

Использовали долгие годы IBM JRE
@
Хуяк, баг в продакшене. Два дня охотились, обложили всё логами, пришли к выводу, что бага в JIT
@
А чего бы не попробовать OpenJDK, вон там даже Shenandoah GC впилили
@
В OpenJDK в JIT нашлась другая бага
@
Смогли составить минимальный тест-кейз, зарепортили
@
В OpenJDK багу починили
@
Пробуем OpenJDK, заебца работает на том проекте, где была бага в IBM JRE

... meanwhile at another project

А попробую ка я впилить BouncyCastle в качестве TLS provider.
@
Хм... никаких улучшений по скорости. Попробую ка туда OpenJDK с Shenandoah GC воткнуть
@
Ну да, стало сильно лучше. Попробую ка дефолтный TLS provider использовать
@
ЕЩЁ ОДНА БАГА В JIT

Мораль: не бывает тривиальных изменений. Если две реализации не противоречат спецификации, то это вовсе не значит, что они не противоречат друг другу.

hirthwork

Что будет если запихнуть 6 миллионов IPv4 значений в HashSet? Большинство скажут, что будет бо-бо, потому что у хэшсета на каждую ноду оверхед в 48 байт на 64-битной машине.
Более опытные разработчики скажут, что оверхед всего 24 байта, потому что java по дефолту использует -XX:UseCompressedOops (a.k.a. -Xcompressedrefs) и при размере памяти меньше 32 ГБ на каждый указатель тратится всего 4 байта.

hirthwork

Здравствуйте, мои маленькие любители поебатися с байткодом. Сегодня я вам расскажу о crucial difference различных access specifiers при объявлении мемберов inner-классов.
Слово в сторону: любой порядочный параноик объявит мембер своего класса как private, а не как либо ещё. Крайне ленивый раздолбай вообще access specifier не напишет. И вот тут-то и зарыта собака.
Возьмём вот такой класс с двумя inner-классами:

public class Main {
    class Inner {
        int field;
    }

    class Pinner {
        private int field;
    }

    int test(final Inner obj) {
        return obj.field;
    }

    int test(final Pinner obj) {
        return obj.field;
    }
}

Ничег сложного, просто два inner-класса, у одного поле int, у другого — private int. Ну и из двух разных функций обращаемся к этим полям.
Скомпилим и посмотрим на байткод:

$ javac Main.java
$ javap -p -c Main.class
Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  int test(Main$Inner);
    Code:
       0: aload_1
       1: getfield      #2                  // Field Main$Inner.field:I
       4: ireturn

  int test(Main$Pinner);
    Code:
       0: aload_1
       1: invokestatic  #3                  // Method Main$Pinner.access$000:(LMain$Pinner;)I
       4: ireturn
}

Ну ничего себе! Было private int простое, а стало золотое — вместо банального getfield получаем invokestatic, который...

$ javap -p -c Main\$Pinner.class
Compiled from "Main.java"
class Main$Pinner {
  private int field;

  final Main this$0;

  Main$Pinner(Main);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #2                  // Field this$0:LMain;
       5: aload_0
       6: invokespecial #3                  // Method java/lang/Object."<init>":()V
       9: return

  static int access$000(Main$Pinner);
    Code:
       0: aload_0
       1: getfield      #1                  // Field field:I
       4: ireturn
}

... внутри уже сам делает getfield, т.е. на ровном месте получили лишний вызов функции. А ещё когда вы сделаете что-то вроде:

Pinner pinner = null;
return pinner.field;

То в стектрейсе NullPointerException вы получите лишний фрейм с этим самым Main$Pinner.access$000, который неопытного программиста просто вводит в ступор.

В общем, я сейчас борюсь с желанием повсюду в коде поудалять все private.

hirthwork

tfw проклятые капиталисты берут на поддержку богохранимую java8 и обещают раздавать секурити апдейты аж до 2023 года без регистрации и смс: http://www.opennet.ru/opennews/art.shtml?num=49623

hirthwork

После двух часов попыток починить то что не ломал, ничто так не греет душу, как аккуратный NullPointerException

hirthwork

Уж если включил -Xverbosegclog, то будь добр, пиши его в /dev/shm/

hirthwork

Здравствуй, дорогой дневничок. Я заебался. Я себе сломал мозг об java.nio.ByteBuffer.
Чтобы не ломать каждый раз, сделал себе удобную пикчу, чтобы сразу было видно, что делает каждая операция.
Попробуйте и вы: https://tinystash.undef.im/...JZCFRvasdjVH7ze5.svg

hirthwork

Словил StackOverflowError от javac

hirthwork

В регулярках джавы можно сделать named capturing groups (если вы не знаете что это такое, то вам не сюда, а в кружок кройки и шитья), и по имени группы из Matcher'а можно доставать captured подстроку. Но при этом из скомпиленной регулярки нельзя достать список имён этих самых capturing groups, которые были заданы в регулярке. Второтег

hirthwork

Иногда ты используешь type erasure, а иногда type erasure имеет тебя

Добавить пост

Вы можете выбрать до 10 файлов общим размером не более 10 МБ.
Для форматирования текста используется Markdown.