Java образец jstack, указывающий на закрывающую скобку, а не на строку кода - PullRequest
0 голосов
/ 20 января 2020

Я пытаюсь отладить проблему с производительностью в Had oop, и как часть этого я несколько раз собирал jstacks из разных сборок oop, работающих на разных Java версиях. Когда у меня возникает проблема с производительностью, я получаю jstack запускаемого потока, например:

"DataXceiver for client DFSClient_NONMAPREDUCE_-619388227_1 at /x.x.x.x:35518 [Sending block BP-1509854702-x.x.x.x-1392815592442:blk_3738093208_1102227094469]" daemon prio=10 tid=0x00007f1a683cf800 nid=0xb61d1 runnable [0x00007f1a36060000]
   java.lang.Thread.State: RUNNABLE
    at org.apache.hadoop.hdfs.util.FoldedTreeSet.get(FoldedTreeSet.java:449)
    at org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.ReplicaMap.get(ReplicaMap.java:111)
    - locked <0x0000000751682590> (a org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl)
    at org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.ReplicaMap.get(ReplicaMap.java:89)
    at org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.getVolume(FsDatasetImpl.java:177)
    - locked <0x0000000751682590> (a org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl)
    at org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.getVolume(FsDatasetImpl.java:127)
    at org.apache.hadoop.hdfs.server.datanode.BlockSender.<init>(BlockSender.java:283)
    at org.apache.hadoop.hdfs.server.datanode.DataXceiver.readBlock(DataXceiver.java:537)
    at org.apache.hadoop.hdfs.protocol.datatransfer.Receiver.opReadBlock(Receiver.java:148)
    at org.apache.hadoop.hdfs.protocol.datatransfer.Receiver.processOp(Receiver.java:103)
    at org.apache.hadoop.hdfs.server.datanode.DataXceiver.run(DataXceiver.java:246)
    at java.lang.Thread.run(Thread.java:744)

Если я проверяю строку 449 исходного кода в верхней части стека, является частью этого метода, и он всегда включен закрывающая фигурная скобка выделена. Каждый раз, когда возникает эта проблема, трассировка стека одинакова, и я видел ее на Java 7 и Java 8.

public E get(Object obj, Comparator<?> cmp) {
    Objects.requireNonNull(obj);

    Node<E> node = root;
    while (node != null) {
      E[] entries = node.entries;

      int leftIndex = node.leftIndex;
      int result = compare(obj, entries[leftIndex], cmp);
      if (result < 0) {
        node = node.left;
      } else if (result == 0) {
        return entries[leftIndex];
      } else {
        int rightIndex = node.rightIndex;
        if (leftIndex != rightIndex) {
          result = compare(obj, entries[rightIndex], cmp);
        }
        if (result == 0) {
          return entries[rightIndex];
        } else if (result > 0) {
          node = node.right;
        } else {
          int low = leftIndex + 1;
          int high = rightIndex - 1;
          while (low <= high) {
            int mid = (low + high) >>> 1;
            result = compare(obj, entries[mid], cmp);
            if (result > 0) {
              low = mid + 1;
            } else if (result < 0) {
              high = mid - 1;
            } else {
              return entries[mid];
            }
          }
          return null;
        }
      }
    } // *** This is line 449 which the jstack always has at the top of the stack.
    return null;
  }

У меня есть другие образцы jstack из того же класса, где выглядят номера строк правильно, и, следовательно, я не думаю, что я смотрю на неправильную версию этого класса. Jstack определенно был захвачен командой jstack из того же самого Java дома, что и тем же пользователем, что и запущенный процесс. Все остальное в примерах выглядит корректно.

Может кто-нибудь предложить какие-либо причины того, почему jstack всегда показывает закрывающую фигурную скобку в качестве строки выполнения? Я никогда не видел этого, прежде чем смотреть на множество выходных данных jstacks.

UPDATE

Исследуя предположение, что это вызвано несоответствием в скомпилированном и исходном коде, я нашел другой пример стека из тот же процесс, что и выше:

"Thread-41" daemon prio=10 tid=0x0000000003c39000 nid=0x1c6fe1 runnable [0x00007f1a4b7b8000]
   java.lang.Thread.State: RUNNABLE
    at org.apache.hadoop.hdfs.util.FoldedTreeSet.removeAndGet(FoldedTreeSet.java:879)
    at org.apache.hadoop.hdfs.util.FoldedTreeSet.removeAndGet(FoldedTreeSet.java:892)
    at org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.ReplicaMap.remove(ReplicaMap.java:162)
    - locked <0x0000000751682590> (a org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl)
    at org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.invalidate(FsDatasetImpl.java:2021)
    - locked <0x0000000751682590> (a org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl)
    at org.apache.hadoop.hdfs.server.datanode.BPOfferService.processCommandFromActive(BPOfferService.java:686)
    at org.apache.hadoop.hdfs.server.datanode.BPOfferService.processCommandFromActor(BPOfferService.java:632)
    at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.processCommand(BPServiceActor.java:729)
    at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.offerService(BPServiceActor.java:539)
    at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.run(BPServiceActor.java:695)
    at java.lang.Thread.run(Thread.java:744)

Это другой метод в том же классе, но код в методе removeAndGet очень похож на код в get. Вот соответствующие фрагменты кода:

  public E removeAndGet(Object obj) {
    return removeAndGet(obj, comparator); // *** This is 892, this is correct as per the stack trace above
  }
  public E removeAndGet(Object obj, Comparator<?> cmp) {
    Objects.requireNonNull(obj);

    if (!isEmpty()) {
      Node<E> node = root;
      while (node != null) {
        E[] entries = node.entries;
        int leftIndex = node.leftIndex;
        int result = compare(obj, entries[leftIndex], cmp);
        if (result < 0) {
          node = node.left;
        } else if (result == 0) {
          return removeElementLeft(node);
        } else {
          int rightIndex = node.rightIndex;
          if (leftIndex != rightIndex) {
            result = compare(obj, entries[rightIndex], cmp);
          }
          if (result == 0) {
            return removeElementRight(node);
          } else if (result > 0) {
            node = node.right;
          } else {
            int low = leftIndex + 1, high = rightIndex - 1;
            while (low <= high) {
              int mid = (low + high) >>> 1;
              result = compare(obj, entries[mid], cmp);
              if (result > 0) {
                low = mid + 1;
              } else if (result == 0) {
                return removeElementAt(node, mid);
              } else {
                high = mid - 1;
              }
            }
            return null;
          }
        }
      } // **** This is 879 - again the same as the get method
    }
    return null;
  }

Код немного позже в исходном файле кажется правильным, но это снова странным образом указывает на фигурные скобки.

1 Ответ

0 голосов
/ 20 января 2020

Это происходит в 99% случаев, когда ваш исходный код и скомпилированный класс не совпадают. Т.е. скомпилированный класс скомпилирован из другого источника (более новая или более старая версия). Thry, чтобы декомпилировать ваш класс (производить. java из .class) Посмотрите, поможет ли это

...