Выделение строки TLAB с помощью socketRead0 - PullRequest
3 голосов
/ 05 января 2020

Окружающая среда:

  1. Linux 4.x
  2. asyn c -профилер 1.6 (https://github.com/jvm-profiling-tools/async-profiler)
  3. OpenJDK8

Код приложения:

Связь между доменом и сокетом через SocketInputStream

Действие:

запуск приложения с помощью асинхронного c профилировщика: - d 60 -e allo c -f /tmp/alloc.svg

Проблема:

неожиданное выделение строки из SocketInputStream # socketRead0

(голубой: TLAB allo c)

enter image description here 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 / native / java / net / 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, поэтому я являюсь идеей.

Кто-нибудь знает, где может происходить распределение строк?

1 Ответ

3 голосов
/ 06 января 2020

Ваше предположение верно. SocketTimeoutException в профиле говорит, что метод выделяет объект исключения, и у этого объекта исключения есть сообщение String, которое также должно быть выделено.

Я только что совершил изменение в asyn c -профиль, который добавляет опцию --cstack для записи стека C вместе со стеком Java в режиме профилирования распределения. Это доказывает, что java.lang.String действительно выделено из функции JNI ThrowNew:

async-profiler

...