Подтвердить что ты не робот

Что означает "устранение" в трассировке стека Java?

Я смотрю на дамп потока моего приложения Java и заметил, что иногда вместо того, чтобы показывать "заблокирован", я вижу ключевое слово "исключено", как показано ниже:

"Worker [4]" prio=10 tid=0x00007fb1262d8800 nid=0x89a0 in Object.wait() [0x00007fb15b147000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:503)
        at com.myapp.common.util.WaitableQueue.getAll(WaitableQueue.java:152)
        - eliminated <0x00000004d0d28e18> (a com.myapp.common.util.balq.SingleQueueQController$_WorkerQueue)
        at com.myapp.common.util.balq.SingleQueueQController$_WorkerQueue.getAll(SingleQueueQController.java:3527)
        - locked <0x00000004d0d28e18> (a com.myapp.common.util.balq.SingleQueueQController$_WorkerQueue)
        at com.myapp.common.util.AbstractWorker.read(AbstractWorker.java:678)
        at com.myapp.common.util.AbstractWorker.runBulk(AbstractWorker.java:541)
        at com.myapp.common.util.AbstractWorker.run(AbstractWorker.java:343)

Удивительно, но я ничего не могу найти в Google об этом. В чем разница между "заблокированными" и "исключенными" ключевыми словами?

4b9b3361

Ответ 1

Он представляет резервную блокировку, которая была удалена в байт-коде.

Я всегда находил исходный код хорошим местом, чтобы начать с таких вещей. В обзоре hotspot/src/share/vm/opto/callnode.cpp от openJDK были следующие интересные комментарии:

// Redundant lock elimination
//
// There are various patterns of locking where we release and
// immediately reacquire a lock in a piece of code where no operations 
// occur in between that would be observable.  In those cases we can
// skip releasing and reacquiring the lock without violating any
// fairness requirements.  Doing this around a loop could cause a lock
// to be held for a very long time so we concentrate on non-looping
// control flow.  We also require that the operations are fully 
// redundant meaning that we don't introduce new lock operations on
// some paths so to be able to eliminate it on others ala PRE.  This
// would probably require some more extensive graph manipulation to
// guarantee that the memory edges were all handled correctly.
//
// Assuming p is a simple predicate which can't trap in any way and s
// is a synchronized method consider this code:
//
//   s();
//   if (p)
//     s();
//   else
//     s();
//   s();
//
// 1. The unlocks of the first call to s can be eliminated if the
// locks inside the then and else branches are eliminated.
//
// 2. The unlocks of the then and else branches can be eliminated if
// the lock of the final call to s is eliminated.
//
// Either of these cases subsumes the simple case of sequential control flow

Таким образом, из приведенного выше, казалось бы, (по крайней мере, в openJDK), который устранен, означает, что блокировка поддерживается JVM через один или несколько наборов инструкций release/получения.

Просмотр javaVFrame::print_lock_info_on() в hotspot/src/share/vm/runtime/vframe.cpp показывает, где происходит проверка и вывод:

// Print out all monitors that we have locked or are trying to lock
GrowableArray<MonitorInfo*>* mons = monitors();
if (!mons->is_empty()) {
  bool found_first_monitor = false;
  for (int index = (mons->length()-1); index >= 0; index--) {
    MonitorInfo* monitor = mons->at(index);
    if (monitor->eliminated() && is_compiled_frame()) { // Eliminated in compiled code
      if (monitor->owner_is_scalar_replaced()) {
        Klass* k = Klass::cast(monitor->owner_klass());
        st->print("\t- eliminated <owner is scalar replaced> (a %s)", k->external_name());
      } else {
        oop obj = monitor->owner();
        if (obj != NULL) {
          print_locked_object_class_name(st, obj, "eliminated");
        }
      }
      continue;

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

Я прочитал документ, который Dirk упомянул в отношении lock elision, и, похоже, это блокировка Coarsening, а не Elision:

Другая оптимизация, которая может быть использована для снижения стоимости блокировки, - это укрупнение замков. Блокировка огрубления - это процесс объединения соседних синхронизированных блоков, которые используют один и тот же объект блокировки. Если компилятор не может устранить блокировку с помощью блокировки, он может уменьшить накладные расходы за счет укрупнения блокировки.

Но, если честно, разница очень тонкая, и конечный эффект почти такой же - вы устраняете ненужные блокировки и разблокировки.