Pull to refresh
170
0
Андрей @apangin

Пользователь

Send message
Да, все правильно.
Полностью соптимизированный код статистику более не собирает и, если вдруг посреди исполнения программы профиль резко поменяется, столкнемся с деградацией производительности.
Это в том случае, если метод все время продолжает исполняться.
Метод, который какое-то время не исполняется, может быть выкинут из CodeCache во время GC и при последующих вызовах будет компилироваться заново.
Девиртуализация работает не так. Учитывается динамический профиль конкретного сценария. Может быть хоть 100 реализаций виртуального метода, но если в конкретном месте конкретного приложения используется преимущественно одна и или две реализации, то данный вызов все равно будет девиртуализован и заинлайнен.
Про SimpleDateFormat и согласен, и несогласен одновременно.
Действительно, это тяжелый метод, который на практике в нашем случае сжирал существенную долю CPU высоконагруженного веб-сервера.
Но я не соглашусь с тем, что виной тому создание нового SimpleDateFormat каждый раз. Медленным здесь является сам процесс конвертации в строку заданного формата. Я эту проблему решил, написав свой конвертер HttpDate, заточенный под конкретный формат, фигурирующий в HTTP протоколе.
* RCT — Runtime Compilation Target
Короткий ответ: ДА.

Если по-длиннее, Jazelle бывает разная. Первоначально так называлась попытка создать JVM в аппаратном исполнении. Отсюда и приставка DBX — Direct Bytecode Execution (а не Dynamic, как написано в русской Википедии). Однако спецификация JVM слишком сложна для того, чтобы ее полностью реализовать в железе. Поэтому Jazelle DBX предусматривает аппаратное исполнение лишь простых байткодов, а сложные отдает на откуп софту. Раньше эта технология позволяла ускорить интерпретацию Java-байткода до 50%, однако как раз с появлением CLDC HI она безнадежно устарела. Несмотря на то, что Jazelle DBX поддерживается в CLDC HI, толк от нее есть только в interpreter-only режиме. При включенной JIT-компиляции DBX только снижает общую производительность.

Jazelle RCT (Runtime Compiler Environment) — совершенно иная технология, не имеющая с DBX ничего общего. RCT — это специальный режим некоторых ARM v7 процессоров, расширяющий Thumb-2 несколькими новыми инструкциями с целью порождения JIT-компиляторами виртуальных машин более компактного и эффективного кода. Примечательно, что в CLDC HI поддержка RCT появилась гораздо раньше, чем само железо. Для реализации использовалась предварительная спецификация от ARM и специально разработанный собственный эмулятор. С выпуском реальных чипов с поддержкой Jazelle RCT, технология сразу заработала в CLDC HI с минимальными изменениями.
IdentityHashMap, кстати, тоже с открытой адресацией.
OK, согласен: Object[] лучше заменить на AtomicReference.

А насчет «код некорректен для написания кем угодно» у меня есть свое мнение: код имеет право на существование до тех пор, пока он решает конкретную задачу в конкретном случае. Мартин Томпсон, которого ты часто цитируешь, тому в пример. Скажем, в многопоточной программе, написанной согласно Single Writer Principle, можно добиться огромного прироста производительности, заменив volatile store на обычный store. Программа будет абсолютно правильно работать на x86 архитектуре, хотя, согласно JMM, будет некорректной.
Это да. Экзотический вариант. Я поэтому и сделал оговорку, что не везде подойдет.
А сам бы я реализовал, как уже сказал, на SynchronousQueue.
И вообще, из всех предложенных вариантов, ИМХО, самый «элегантный» — с Exchanger.
Согласен :)
А я не совсем :) Exchanger служит для двустороннего обмена, а в данном примере имеет место односторонний (producer-consumer). ИМХО лучше всего подходит SynchronousQueue. И по длине кода столько же: один exchange меняется на put, а второй — на take.
The park method may also return at any other time, for «no reason»
На практике этого никогда не произойдет, т.к. HotSpot фильтрует «случайные» пробуждения.
Но synchronized в любом случае не нужен. В том-то и «фишка» LockSupport: park() можно вызывать даже после того, как случился unpark() — дедлока не будет.
Все синхронизационные примитивы java.util.concurrent (ReentrantLock, Semaphore, ArrayBlockingQueue, Exchanger и т.д.) реализованы на основе LockSupport.
Вот еще интересный короткий метод, хотя и не для всех случаев годится:

static Object syncMethod() {
    final Object[] result = new Object[1];
    final Thread caller = Thread.currentThread();

    A.asyncMethod(new Callback() {
        @Override
        public void onFinish(Object obj) {
            result[0] = obj;
            LockSupport.unpark(caller);
        }
    });

    LockSupport.park();
    return result[0];
}
Делать wait / notify на BlockingQueue — это оскорбление всего Java Concurrency.
BlockingQueue на то и blocking, что вызов take() будет ждать, пока в очередь не поступит элемент из другого потока.
… которая вылетает с ошибкой (segfault). Обычно студенты в таких ситуациях используют деление на ноль.
Если понимать буквально, то деление на ноль вызывает вовсе не segmentation fault, а SIGFPE.
Сегфолты связаны с ошибками обращения к памяти, и main=0 — как раз такой случай.
Если уж и клиент, и агент все равно отдельные самописные, то смысл использовать JMX/RMI? Стандартный RMI тяжеловесный и медленный с побочными эффектами типа периодического Full GC. Клиент на Java — тоже не лучший выбор, особенно, когда мониторинг дергается очень часто.
У нас, например, агент отдает статистику plain text'ом по HTTP, а Cacti забирает ее просто curl'ом.
IMPORTANT: Java 7 update 17 still has no changes in the subject of this article.
ВАЖНО: 17 апдейт 7 версии Java не содержит изменений, описанных в этой статье.
По-моему, смысл перевода получился диаметрально противоположным.
Для null, очевидно, хеш-код не генерируется. Но System.identityHashCode(null) возвращает 0 — все верно.
Ну раз вы такой умный, киньте кусочек исходного кода из пакета java.lang, где используется Random в hashCode().
Отвечу в поддержку SSSurkv:
hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/share/vm/runtime/synchronizer.cpp, стр. 537.
Этот код выполняется при вызове Object.hashCode() и System.identityHashCode() в HotSpot JVM.
Именно ГСЧ и используется в HotSpot для вычисления hashCode в первый раз на объекте (см. synchronizer.cpp, стр. 537).
А какой бы вы предложили вариант для вычисления identityHashCode без ГСЧ?
Популярное заблуждение — использовать адрес объекта — не подходит по ряду причин: адрес объекта изменяется во время GC, кроме того, выделяемые подряд объекты будут иметь последовательные хеш-коды.
Заминусовали очень правильный комментарий!
Если Dalvik VM в качестве Object.hashCode() использует адрес объекта, то всем известный HotSpot совершенно точно для первого вычисления hashCode объекта использует random (см. стр. 537). Далее полученное число сохраняется в заголовке объекта для последующих вызовов hashCode.
Мы, значит, делаем все возможное, чтобы по-максимуму использовать Java-решения, а вы нам тут C настоятельно советуете?.. Шучу, ничего не имею против. За Varnish спасибо. Впрочем, любое стандартное решение в чистом виде нам вряд ли подойдет, так как в любом случае нужна некоторая портало-специфичная логика, например, фильтрация по HTTP-заголовкам, проверка security-токенов в запросах и т.п. Malloc в чистом виде опять же не подойдет — т.к. при рестарте все теряется.

На самом деле, медленность Java по сравнению с C сильно преувеличивается. И, в частности, этой статьей я хотел показать, что на Java можно писать высокопроизводительные приложения, не уступающие программам на C.

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Works in
Registered
Activity