Распределение строк TLAB по socketRead0
Окружающая среда:
- Linux 4.x
- async-profiler 1.6 (https://github.com/jvm-profiling-tools/async-profiler)
- OpenJDK8
Код приложения:
Связь домен-сокет через SocketInputStream
Действие:
запустить приложение с помощью асинхронного профилировщика: -d 60 -e alloc -f /tmp/alloc.svg
Проблема:
неожиданное выделение строки из SocketInputStream # socketRead0
(голубой: выделение TLAB)
JDK-код для socketRead и socketRead0
private int socketRead(FileDescriptor fd,
byte b[], int off, int len,
int timeout)
throws IOException {
return socketRead0(fd, b, off, len, timeout);
}
private native int socketRead0(FileDescriptor fd,
byte b[], int off, int len,
int timeout)
родной Socket-Impl:
- JDK / SRC / Solaris / собственный / Java / сеть /SocketInputStream.c
Предположение:
Строка, вероятно, выделяется в java-heap через JNI где-то в следующем коде, потому что в StackTrace прямо рядом с выделением строки есть SocketTimeoutException
Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this,
jobject fdObj, jbyteArray data,
jint off, jint len, jint timeout)
{
[...]
if (timeout) {
nread = NET_ReadWithTimeout(env, fd, bufP, len, timeout);
if ((*env)->ExceptionCheck(env)) {
if (bufP != BUF) {
free(bufP);
}
return nread;
}
} else {
nread = NET_Read(fd, bufP, len);
}
[...]
}
static int NET_ReadWithTimeout(JNIEnv *env, int fd, char *bufP, int len, long timeout) {
int result = 0;
long prevtime = NET_GetCurrentTime(), newtime;
while (timeout > 0) {
result = NET_TimeoutWithCurrentTime(fd, timeout, prevtime);
if (result <= 0) {
if (result == 0) {
JNU_ThrowByName(env, "java/net/SocketTimeoutException", "Read timed out");
} else if (result == -1) {
if (errno == EBADF) {
JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
} else if (errno == ENOMEM) {
JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
} else {
JNU_ThrowByNameWithMessageAndLastError
(env, "java/net/SocketException", "select/poll failed");
}
}
return -1;
}
result = NET_NonBlockingRead(fd, bufP, len);
if (result == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
newtime = NET_GetCurrentTime();
timeout -= newtime - prevtime;
if (timeout > 0) {
prevtime = newtime;
}
} else {
break;
}
}
return result;
}
Я искал C-код и не нашел никаких выделений jString, поэтому я своего рода идеи.
Кто-нибудь знает, где может произойти распределение String?
1 ответ
Ваше предположение верно. SocketTimeoutException
в профиле сообщает, что метод выделяет объект исключения, и этот объект исключения имеет String
сообщение, которое также необходимо выделить.
Я только что внес изменение в async-profiler, которое добавляет --cstack
опция для записи стека C вместе со стеком Java в режиме профилирования распределения. Это доказывает, чтоjava.lang.String
действительно выделяется из JNI ThrowNew
функция: