Я пытаюсь отладить проблему с производительностью в 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;
}
Код немного позже в исходном файле кажется правильным, но это снова странным образом указывает на фигурные скобки.