Как происходит распределение памяти и как Java и C взаимодействуют, чтобы отслеживать один и тот же объект? - PullRequest
1 голос
/ 24 сентября 2019

У меня есть класс, содержащий переменную-член типа long и набор объявлений собственных методов.Я считаю, что память для переменной выделяется в одном из собственных методов, и попытка отмены выделения выполняется в методе finalize () путем вызова другого собственного метода destroy.Я понимаю, что finalize устарела, но прежде чем найти альтернативу для finalize, мне нужно понять, как происходит распределение памяти и как Java и C поддерживают синхронизацию через JNI и как отслеживается эта конкретная переменная-член.Я попытаюсь объяснить сценарий лучше с помощью фрагментов кода:

JSQ.java

class JSQ {
    protected long shdl;
    protected JSQ() { log("JSQ constructor"); }
    protected JSQ(String stmt, boolean isd)
        throws DhSQLException
    {
        // calls a set of native methods
        set_shdl();
        setstmt(stmt, shdl);
        setd(isd, shdl);
        prep(shdl);
    }

    public void finalize()
    {
        destroy(shdl);
    }

    private native void set_shdl() throws DhSQLException;
    private native void setstmt(String s, long shdl) throws DhSQLException;
    private native void setd(boolean b, long shdl);
    private native void prep(long shdl) throws DhSQLException;
    private native void destroy(long shdl);

    protected void execute() throws DhSQLException
    {
        parExec(shdl);
    }

    protected native void parExec(long shdl);
}

JSQL.cxx

#define SQ ((sq_stsm_t *)(shdl))

JNIEXPORT void JNICALL Java_com_project_package_JSQ_set_shdl
(JNIEnv *env, jobject obj_This)
{
    jclass cls;
    jmethodID mid;
    cls = (env)->GetObjectClass (obj_This);
    mid = (env)->GetMethodID (hThis,"set_JSQ_shdl","(J)V");

    status_t status;
    // memory allocation
    sq_stsm_t * S = new sq_stsm_t(status);
    if(status)
    {
        if (S) { delete S; }
        return;
    }
    // I understand that we're attempting to call a Java method from a native method.
    // But which method is it calling?
    // Also, are we converting S from sq_stms_t type to jlong?
    (env)->CallVoidMethod (obj_This,mid,(jlong) S);
    return;
}

JNIEXPORT void JNICALL Java_com_project_package_JSQ_setstmt
(JNIEnv *env, jobject, jstring jstmt, jlong shdl)
{
    status_t status;

    // cstmt is obtained using jstmt

    // Note: #define SQ ((sq_stsm_t *)(shdl))
    status = SQ->SetStmt(cstmt);

    return;
}

JNIEXPORT void JNICALL Java_com_project_package_JSQ_destroy
(JNIEnv *, jobject, jlong shdl)
{
    delete SQ;
}

Точки, в которых я запутался:

  1. Почему long и jlong ​​и преобразование из определенного пользователем типа sq_stsm_t в long.Я понимаю, что Java не знает об этом определяемом пользователем типе.Но почему выбор long?

  2. Почему #define на SQ и как именно уничтожить удаляет память, выделенную в set_shdl, вызывая delete на SQ?

Опубликуйте это, я должен найти замену для финализации - для которой я пришел к выводу, что AutoCloseable с try-with-resources, безусловно, мой лучший вариант.Так как здесь задействовано много местных вызовов, я не понимаю, как мне поступить.Но это отдельный вопрос, и я не хочу вдаваться в подробности.Просто упомяну, чтобы установить некоторый фон для варианта использования.

1 Ответ

3 голосов
/ 24 сентября 2019

Переменная Java long гарантированно имеет ширину 64 бита, поэтому ее достаточно для хранения адреса даже в 64-битной системе.Приведение к long просто для того, чтобы осчастливить систему типов C ++.Как видите, макрос SQ используется для преобразования этого адреса обратно в правильный указатель на объект sq_stsm_t.

Что касается вашего второго вопроса: все, что делает макрос, это избавляется от некоторой работы при наборе текста,Java-часть вашей программы всегда будет передавать переменную long -типа shdl, поэтому макрос SQ просто обеспечивает легкий доступ к реальному объекту sq_stsm_t.

Наконец, new иdelete в C ++ идут вместе: new выделяет память и вызывает конструктор, delete вызывает деструктор и снова освобождает память.Обратите внимание, что «свободный» не обязательно означает «вернуть ОС», поэтому использование памяти вашим процессом может оставаться неизменным после этой операции delete.

Что касается комментария в вашем коде: Java_com_project_package_JSQ_set_shdlпытается вызвать метод Java boolean com.project.package.JSQ#set_JSQ_shdl(jlong), хотя его нет в коде, который вы вставили.Я полагаю, это простой установщик для поля shdl?

Что касается ваших последующих планов: реализация AutoCloseable - хорошая идея.Вам потребуется создать метод native void close() в вашем объекте JSQ, который вызывает delete для объекта sq_stsm_t, хранящегося в поле shdl, а затем заменяет поле shdl на (jlong)nullptr.

...