Необычный и изворотливый сбой Android во время загрузки кода JNI / OpenGL ES - PullRequest
5 голосов
/ 04 августа 2011

Щедрость

Так как это важная проблема для меня, я наложил на него награду.Я не ищу точного ответа - любой ответ заставляет меня решить эту проблему, получает награду.Пожалуйста, убедитесь, что вы видели правку чуть ниже.

Правка: с тех пор мне удалось поймать сбой в Gdb, как только он умирает (через "adb shell setprop debug.db.uid 32767") изаметил, что это та же самая проблема, которая упоминается в этом сообщении в группах Google.Показанная обратная трассировка такая же (за исключением точных адресов), как и у моего аварийного потока.Я признаю, я не мастер отладки, поэтому, если у вас есть идеи о том, что мне нужно искать, пожалуйста, дайте мне знать.

Быстрое и грязное краткое изложение

IВычеркнули большую часть кода моего достаточно большого приложения, чтобы приложение выполняло следующие действия: загружает кучу текстур через оболочки JNI (из C ++ -> Java), чтобы библиотеки Java обрабатывали декодирование для меня, делаетOpenGL текстуры из них, и очищает экран до довольно красивый, но насмешливый темно-синий цвет.Он умирает в libc, но только один раз в десять раз.

Что еще хуже, даже не похоже, что он умирает из-за какого-либо кода, который я написал - похоже, это происходит вотложенная мода, но, кажется, это не связано с чем-то таким же удобным, как сборщик мусора.В моем собственном коде нет особой точки, в которой происходит сбой - кажется, что она меняется с каждым прогоном.

Чем длиннее история

Я заканчиваю сстандартный аварийный дамп со стеком, который мне ни о чем не говорит, потому что у него есть две записи: одна в libc, а другая в том, что выглядит как недопустимый или нулевой фрейм стека.Разрешенным символом в libc является pthread_mutex_unlock.Я больше даже не использую эту функцию, поскольку избавился от необходимости многопоточности.(Собственный код вызывается в виде поверхности и просто выполняет рендеринг.)

pthread_mutex_unlock приводит к ошибке сегментации, обычно по адресу 0, но иногда с небольшим значением (менее 0x200) вместо 0. По умолчанию (и самое распространенное) мьютекс в Bionic имеет только один указатель, на который он может переключиться, и это указатель на саму структуру pthread_mutex_t.Однако более сложный мьютекс (есть несколько вариантов) может использовать дополнительные указатели.Таким образом, есть вероятность, что libc в порядке, и у libdvm есть проблема (при условии, что я могу доверять своей трассировке стека даже в такой степени).

Позвольте мне заметить, что эта проблема кажется воспроизводимой, только если я сделаю одну из этих двух вещей: отключить загрузку в части данных изображений (но все еще считывать информацию о формате / размере) и оставить буфер, который я использую для загрузки текстур в OpenGL, неинициализированным, или отключить создание текстуры OpenGL, отключив только последний вызов glTexImage2D.

Обратите внимание, что вышеупомянутый буфер для загрузки текстур в OpenGL создается только один раз и уничтожается один раз.Я попытался увеличить его и решил, что меня не беспокоит проблема переполнения буфера, специфичная для этого буфера.

Основные виновники, о которых я могу подумать:

  • I 'Я не правильно использую JNI, и он делает что-то неприятное со стеком.
  • У меня есть ошибка, которая повреждает кадр стека.
  • Я передаю OpenGL ES что-то плохоеи он делает что-то одинаково плохо (тм).
  • Мой распределенный по памяти распределитель памяти не работает должным образом.

Я прочесывал свой код для таких преступников (и не только!) несколько дней.Я не решаюсь использовать отладчик, потому что этот сбой, кажется, чувствителен к времени.Тем не менее, я все еще могу получить сбой с моим собственным собственным кодом, полностью не оптимизированным с включенными параметрами отладки.(сам gdb запускается при сканировании, как и приложение, когда оно подключено)

То, что я сделал

  • Используется CheckJNI.
  • Урезано докод, как я могу, пока он не перестанет падать.
  • Написал обработчик сигнала и закодировал небольшую систему регистрации, чтобы выгрузить последние вещи, сделанные до того, как сигнал был брошен.
  • Пытался (и не смог) обострить проблему.
  • Проложенные массивы кучи с обеих сторон с канареками. Они никогда не менялись.
  • Проверено 100% кода в пути кода. (Я просто не вижу проблемы.)
  • Думал, что проблема волшебным образом исчезла, когда я исправил небольшую ошибку, выполнил код пятьдесят раз, чтобы убедиться, что это так, и затем на следующий день вышел из строя при первом запуске. (Ох, я никогда раньше не был так зол на ошибку!)

Вот фрагмент обычной информации о падении из LogCat:

I/DEBUG   ( 5818): signal 11 (SIGSEGV), fault addr 00000000
I/DEBUG   ( 5818):  r0 0000006e  r1 00000080  r2 fffffc5e  r3 100ffe58
I/DEBUG   ( 5818):  r4 00000000  r5 00000000  r6 00000000  r7 00000000
I/DEBUG   ( 5818):  r8 00000000  r9 8054f999  10 10000000  fp 0013e768
I/DEBUG   ( 5818):  ip 3b9aca00  sp 100ffe58  lr afd10640  pc 00000000  cpsr 60000010
I/DEBUG   ( 5818):  d0  643a64696f72646e  d1  6472656767756265
I/DEBUG   ( 5818):  d2  8083297880832965  d3  8083298880832973
I/DEBUG   ( 5818):  d4  8083291080832908  d5  8083292080832918
I/DEBUG   ( 5818):  d6  8083293080832928  d7  8083294880832938
I/DEBUG   ( 5818):  d8  0000000000000000  d9  0000000000000000
I/DEBUG   ( 5818):  d10 0000000000000000  d11 0000000000000000
I/DEBUG   ( 5818):  d12 0000000000000000  d13 0000000000000000
I/DEBUG   ( 5818):  d14 0000000000000000  d15 0000000000000000
I/DEBUG   ( 5818):  d16 0000000000000000  d17 3fe999999999999a
I/DEBUG   ( 5818):  d18 42eccefa43de3400  d19 3fe00000000000b4
I/DEBUG   ( 5818):  d20 4008000000000000  d21 3fd99a27ad32ddf5
I/DEBUG   ( 5818):  d22 3fd24998d6307188  d23 3fcc7288e957b53b
I/DEBUG   ( 5818):  d24 3fc74721cad6b0ed  d25 3fc39a09d078c69f
I/DEBUG   ( 5818):  d26 0000000000000000  d27 0000000000000000
I/DEBUG   ( 5818):  d28 0000000000000000  d29 0000000000000000
I/DEBUG   ( 5818):  d30 0000000000000000  d31 0000000000000000
I/DEBUG   ( 5818):  scr 80000012
I/DEBUG   ( 5818): 
I/DEBUG   ( 5818):          #00  pc 00000000  
I/DEBUG   ( 5818):          #01  pc 0001063c  /system/lib/libc.so
I/DEBUG   ( 5818): 
I/DEBUG   ( 5818): code around pc:
I/DEBUG   ( 5818): 
I/DEBUG   ( 5818): code around lr:
I/DEBUG   ( 5818): afd10620 e1a01008 e1a02007 e1a03006 e1a00005 
I/DEBUG   ( 5818): afd10630 ebfff95d e1a05000 e1a00004 ebffff46 
I/DEBUG   ( 5818): afd10640 e375006e 03a0006e 13a00000 e8bd81f0 
I/DEBUG   ( 5818): afd10650 e304cdd3 e3043240 e92d4010 e341c062 
I/DEBUG   ( 5818): afd10660 e1a0e002 e24dd008 e340300f e1a0200d 
I/DEBUG   ( 5818): 
I/DEBUG   ( 5818): stack:
I/DEBUG   ( 5818):     100ffe18  00000000  
I/DEBUG   ( 5818):     100ffe1c  00000000  
I/DEBUG   ( 5818):     100ffe20  00000000  
I/DEBUG   ( 5818):     100ffe24  ffffff92  
I/DEBUG   ( 5818):     100ffe28  100ffe58  
I/DEBUG   ( 5818):     100ffe2c  00000000  
I/DEBUG   ( 5818):     100ffe30  00000080  
I/DEBUG   ( 5818):     100ffe34  8054f999  /system/lib/libdvm.so
I/DEBUG   ( 5818):     100ffe38  10000000  
I/DEBUG   ( 5818):     100ffe3c  afd10640  /system/lib/libc.so
I/DEBUG   ( 5818):     100ffe40  00000000  
I/DEBUG   ( 5818):     100ffe44  00000000  
I/DEBUG   ( 5818):     100ffe48  00000000  
I/DEBUG   ( 5818):     100ffe4c  00000000  
I/DEBUG   ( 5818):     100ffe50  e3a07077  
I/DEBUG   ( 5818):     100ffe54  ef900077  
I/DEBUG   ( 5818): #01 100ffe58  00000000  
I/DEBUG   ( 5818):     100ffe5c  00000000  
I/DEBUG   ( 5818):     100ffe60  00000000  
I/DEBUG   ( 5818):     100ffe64  00000000  
I/DEBUG   ( 5818):     100ffe68  00000000  
I/DEBUG   ( 5818):     100ffe6c  00000000  
I/DEBUG   ( 5818):     100ffe70  00000000  
I/DEBUG   ( 5818):     100ffe74  00000000  
I/DEBUG   ( 5818):     100ffe78  00000000  
I/DEBUG   ( 5818):     100ffe7c  00000000  
I/DEBUG   ( 5818):     100ffe80  00000000  
I/DEBUG   ( 5818):     100ffe84  00000000  
I/DEBUG   ( 5818):     100ffe88  00000000  
I/DEBUG   ( 5818):     100ffe8c  00000000  
I/DEBUG   ( 5818):     100ffe90  00000000  
I/DEBUG   ( 5818):     100ffe94  00000000  
I/DEBUG   ( 5818):     100ffe98  00000000  
I/DEBUG   ( 5818):     100ffe9c  00000000  

Использование ndk r6, платформа Android 2.2 (уровень API 8), компиляция с -Wall -Werror, только в режиме ARM.

Я смотрю на любые идеи, особенно те, которые можно проверить детерминистическим способом. Если больше информации поможет, просто оставьте комментарий (или, если вы не можете, ответ), и я обновлю свой вопрос как можно скорее. Спасибо за чтение этого далеко!

Интерфейс JNI

Есть как j2n, так и n2j звонки. Единственные j2n звонки сейчас здесь:

private static class Renderer implements GLSurfaceView.Renderer {
    public void onDrawFrame(GL10 gl) {
        GraphicsLib.graphicsStep();
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GraphicsLib.graphicsInit(width, height);
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // Do nothing.
    }
}

Этот код проходит через этот интерфейс:

public class GraphicsLib {

     static {
         System.loadLibrary("graphicslib");
     }

     public static native void graphicsInit(int width, int height);
     public static native void graphicsStep();
}

Что на родной стороне выглядит так:

extern "C" {
    JNIEXPORT void JNICALL FN(graphicsInit)(JNIEnv* env, jobject obj,  jint width, jint height);
    JNIEXPORT void JNICALL FN(graphicsStep)(JNIEnv* env, jobject obj);
};

Сами определения функций начинаются с копии прототипов.

graphicsInit просто хранит размеры, которые были переданы, и немного настраивает OpenGL без чего-либо особенно интересного. graphicsStep очищает экран до приятного цвета и вызывает LoadSprites(env).

Более сложная сторона состоит из вызовов n2j, используемых в LoadSprites (), которая загружает в спрайт каждый кадр. Не элегантное решение, но оно работает за исключением этого сбоя.

LoadSprites работает так:

GameAssetsInfo gai;
void LoadSprites(JNIEnv* env)
{
    InitGameAssets(gai, env);
    CatchJNIException(env, "j0");
    ...
    static int z = 0;
    if (z < numSprites)
    {
        CatchJNIException(env, "j1");
        OpenGameImage(gai, SpriteIDFromNumber(z));
        CatchJNIException(env, "j2");
        unsigned int actualWidth = GetGameImageWidth(gai);
        CatchJNIException(env, "j3");
        unsigned int actualHeight = GetGameImageHeight(gai);
        CatchJNIException(env, "j4");
        ...
        jint i;
        int r = 0;
        CatchJNIException(env, "j5");
        do {
            CatchJNIException(env, "j6");
            i = ReadGameImage(gai);
            CatchJNIException(env, "j7");
            if (i > 0)
            {
                // Deal with the pure data chunk -- One line at a time.
                CatchJNIException(env, "j8");
                StoreGameImageChunk(gai, (int*)sprites[z].data + r, 0, i);
                ...
                r += sprites[z].width;
                CatchJNIException(env, "j9");
                UnreadGameImage(gai);
                CatchJNIException(env, "j10");
            } else {
                break;
            }
        } while (true);

        CatchJNIException(env, "j11");
        CloseGameImage(gai);
        CatchJNIException(env, "j12");

        ... OpenGL ES calls ...

        glTexImage2D( ... );

        z++;
    }

    CatchJNIException(env, "j13");
}

Где CatchJNIException (а никогда ничего не печатает для меня):

void CatchJNIException(JNIEnv* env, const char* str)
{
    jthrowable exc = env->ExceptionOccurred();
    if (exc) {
        jclass newExcCls;
        env->ExceptionDescribe();
        env->ExceptionClear();
        newExcCls = env->FindClass( 
            "java/lang/IllegalArgumentException");
        if (newExcCls == NULL) {
            // Couldn't find the exception class.. Uuh..
            LOGE("Failed to catch JNI exception entirely -- could not find exception class.");
            return;
            abort();
        }
        LOGE("Caught JNI exception. (%s)", str);
        env->ThrowNew( newExcCls, "thrown from C code");
//      abort();
    }
}

А соответствующая часть GameAssetInfo и связанный с ней код вызывается только из собственного кода и работает следующим образом:

void InitGameAssets(GameAssetsInfo& gameasset, JNIEnv* env)
{
    CatchJNIException(env, "jS0");
    FST;
    char str[64];
    sprintf(str, "%s/GameAssets", ROOTSTR);

    gameasset.env = env;
    CatchJNIException(gameasset.env, "jS1");
    gameasset.cls = gameasset.env->FindClass(str);
    CatchJNIException(gameasset.env, "jS2");
    gameasset.openAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "OpenAsset", "(I)V");
    CatchJNIException(gameasset.env, "jS3");
    gameasset.readAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "ReadAsset", "()I");
    CatchJNIException(gameasset.env, "jS4");
    gameasset.closeAsset = gameasset.env->GetStaticMethodID(gameasset.cls, "CloseAsset", "()V");
    CatchJNIException(gameasset.env, "jS5");
    gameasset.buffID = gameasset.env->GetStaticFieldID(gameasset.cls, "buff", "[B");

    CatchJNIException(gameasset.env, "jS6");
    gameasset.openImage = gameasset.env->GetStaticMethodID(gameasset.cls, "OpenImage", "(I)V");
    CatchJNIException(gameasset.env, "jS7");
    gameasset.readImage = gameasset.env->GetStaticMethodID(gameasset.cls, "ReadImage", "()I");
    CatchJNIException(gameasset.env, "jS8");
    gameasset.closeImage = gameasset.env->GetStaticMethodID(gameasset.cls, "CloseImage", "()V");
    CatchJNIException(gameasset.env, "jS9");
    gameasset.buffIntID = gameasset.env->GetStaticFieldID(gameasset.cls, "buffInt", "[I");
    CatchJNIException(gameasset.env, "jS10");
    gameasset.imageWidth = gameasset.env->GetStaticFieldID(gameasset.cls, "imageWidth", "I");
    CatchJNIException(gameasset.env, "jS11");
    gameasset.imageHeight = gameasset.env->GetStaticFieldID(gameasset.cls, "imageHeight", "I");
    CatchJNIException(gameasset.env, "jS12");
    gameasset.imageHasAlpha = gameasset.env->GetStaticFieldID(gameasset.cls, "imageHasAlpha", "I");
    CatchJNIException(gameasset.env, "jS13");
}

void OpenGameAsset(GameAssetsInfo& gameasset, int rsc)
{
    FST;
    CatchJNIException(gameasset.env, "jS14");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.openAsset, rsc);
    CatchJNIException(gameasset.env, "jS15");
}

void CloseGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS16");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.closeAsset);
    CatchJNIException(gameasset.env, "jS17");
}

int ReadGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS18");
    int ret = gameasset.env->CallStaticIntMethod(gameasset.cls, gameasset.readAsset);
    CatchJNIException(gameasset.env, "jS19");
    if (ret > 0)
    {
    CatchJNIException(gameasset.env, "jS20");
        gameasset.obj = gameasset.env->GetStaticObjectField(gameasset.cls, gameasset.buffID);
    CatchJNIException(gameasset.env, "jS21");
        gameasset.arr = reinterpret_cast<jbyteArray*>(&gameasset.obj);
    }
    return ret;
}

void UnreadGameAsset(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS22");
    gameasset.env->DeleteLocalRef(gameasset.obj);
    CatchJNIException(gameasset.env, "jS23");
}

void StoreGameAssetChunk(GameAssetsInfo& gameasset, void* store, int offset, int length)
{
    FST;
    CatchJNIException(gameasset.env, "jS24");
    gameasset.env->GetByteArrayRegion(*gameasset.arr, offset, length, (jbyte*)store);
    CatchJNIException(gameasset.env, "jS25");
}

void OpenGameImage(GameAssetsInfo& gameasset, int rsc)
{
    FST;
    CatchJNIException(gameasset.env, "jS26");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.openImage, rsc);
    CatchJNIException(gameasset.env, "jS27");
    gameasset.l_imageWidth = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageWidth);
    CatchJNIException(gameasset.env, "jS28");
    gameasset.l_imageHeight = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageHeight);
    CatchJNIException(gameasset.env, "jS29");
    gameasset.l_imageHasAlpha = (int)gameasset.env->GetStaticIntField(gameasset.cls, gameasset.imageHasAlpha);
    CatchJNIException(gameasset.env, "jS30");
}

void CloseGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS31");
    gameasset.env->CallStaticVoidMethod(gameasset.cls, gameasset.closeImage);
    CatchJNIException(gameasset.env, "jS32");
}

int ReadGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS33");
    int ret = gameasset.env->CallStaticIntMethod(gameasset.cls, gameasset.readImage);
    CatchJNIException(gameasset.env, "jS34");
    if ( ret > 0 )
    {
        CatchJNIException(gameasset.env, "jS35");
        gameasset.obj = gameasset.env->GetStaticObjectField(gameasset.cls, gameasset.buffIntID);
        CatchJNIException(gameasset.env, "jS36");
        gameasset.arrInt = reinterpret_cast<jintArray*>(&gameasset.obj);
    }
    return ret;
}

void UnreadGameImage(GameAssetsInfo& gameasset)
{
    FST;
    CatchJNIException(gameasset.env, "jS37");
    gameasset.env->DeleteLocalRef(gameasset.obj);
    CatchJNIException(gameasset.env, "jS38");
}

void StoreGameImageChunk(GameAssetsInfo& gameasset, void* store, int offset, int length)
{
    FST;
    CatchJNIException(gameasset.env, "jS39");
    gameasset.env->GetIntArrayRegion(*gameasset.arrInt, offset, length, (jint*)store);
    CatchJNIException(gameasset.env, "jS40");
}

int GetGameImageWidth(GameAssetsInfo& gameasset) { return gameasset.l_imageWidth; }
int GetGameImageHeight(GameAssetsInfo& gameasset) { return gameasset.l_imageHeight; }
int GetGameImageHasAlpha(GameAssetsInfo& gameasset) { return gameasset.l_imageHasAlpha; }

И это поддерживается на стороне Java:

public class GameAssets {
    static public Resources res = null;
    static public InputStream is = null;
    static public byte buff[];
    static public int buffInt[];
    static public final int buffSize = 1024;
    static public final int buffIntSize = 2048;

    static public int imageWidth;
    static public int imageHeight;
    static public int imageHasAlpha;
    static public int imageLocX;
    static public int imageLocY;
    static public Bitmap mBitmap;
    static public BitmapFactory.Options decodeResourceOptions = new BitmapFactory.Options();

    public GameAssets(Resources r) {
        res = r;
        buff = new byte[buffSize];
        buffInt = new int[buffIntSize];
        decodeResourceOptions.inScaled = false;
    }
    public static final void OpenAsset(int id) {
        is = res.openRawResource(id);
    }
    public static final int ReadAsset() {
        int num = 0;
        try {
            num = is.read(buff);
        } catch (Exception e) {
            ;
        }
        return num;
    }
    public static final void CloseAsset() {
        try {
            is.close();
        } catch (Exception e) {
            ;
        }
        is = null;
    }

    // We want all the advantages that BitmapFactory can provide -- reading
    // images of compressed image formats -- so we provide our own interface
    // for it.
    public static final void OpenImage(int id) {
        mBitmap = BitmapFactory.decodeResource(res, id, decodeResourceOptions);
        imageWidth = mBitmap.getWidth();
        imageHeight = mBitmap.getHeight();
        imageHasAlpha = mBitmap.hasAlpha() ? 1 : 0;
        imageLocX = 0;
        imageLocY = 0;
    }
    public static final int ReadImage() {
        if (imageLocY >= imageHeight) return 0;
        int numReadPixels = buffIntSize;
        if (imageLocX + buffIntSize >= imageWidth)
        {
            numReadPixels = imageWidth - imageLocX;
            mBitmap.getPixels(buffInt, 0, imageWidth, imageLocX, imageLocY, numReadPixels, 1);
            imageLocY++;
        }
        else
        {
            mBitmap.getPixels(buffInt, 0, imageWidth, imageLocX, imageLocY, numReadPixels, 1);
            imageLocX += numReadPixels;
        }
        return numReadPixels;
    }
    public static final void CloseImage() {
    }
}

Обратите внимание на явное отсутствие безопасности потоков в коде игрового ресурса.

Дайте мне знать, будет ли полезной дополнительная информация.

Ответы [ 4 ]

1 голос
/ 16 августа 2011

Публикация из моих предыдущих комментариев. «Может произойти исключение JNI, и, поскольку вы не вернетесь после исключения, это может вызвать сбой. Я не знаю, как работает регистрация в Android, но в C простой printf не нужно выводить журнал сразу. в сценарии, когда произошел сбой, могло произойти исключение, но произошел сбой системы перед выводом журнала "
Не был онлайн в течение нескольких дней. Надеюсь, что крушение не вернется .. Я ненавижу, когда некоторые проблемы волшебным образом исчезают без четкого объяснения. Они обычно возвращаются и кусают тебя ;-) В любом случае, надеюсь, что тебя не укусят

1 голос
/ 12 августа 2011

Поначалу это может показаться глупым, но ваша проблема напоминает мне о проблеме, возникшей у нас в одном из наших приложений для Android. Мы старались быть оптимальными, используя «статические» объекты для вещей, которые, как мы были уверены, должны существовать только один раз, и мы хотим, чтобы их создавали только один раз. Похоже, это противоречило нашему жизненному циклу Деятельности в Android (после многих отладок и головной боли), поэтому мы переключились на использование экземпляров и позволили ОС обрабатывать очистку и оптимизацию Деятельности. Это решило нашу проблему, и наше приложение было достаточно стабильным.

1 голос
/ 09 августа 2011

Я не могу дать ответ :(, у меня просто была похожая проблема, и я заметил, что java-документ где-то говорит, что есть потоки (если вы используете OpenGL, то есть потоки). Вам нужно быть осторожным с первым параметром(env) и второй параметр (jobject). Вы не можете совместно использовать его в разных потоках, потому что они зависят от потока.

Для моего случая есть поток событий и поток рендеринга. У меня был глобальный env & jselfПеременные, которые были 2 параметрами, переданными при вызове jni. Я изменил свой код, чтобы убедиться, что только поток рендеринга касается переменных env / jself. В потоке событий я передаю примитивные данные и просто отмечаю, что нужно сделатьтаким образом, не нужны переменные env / jself. Конечно, я использую мьютексы для блокировки моей структуры событий.

похоже, что вы устанавливаете env здесь потенциально глобально gameasset.env = env;

, если gameasset глобалени / или используются другими потоками, просто разделяя env или переменную класса jobjectвзаимные блокировки / блокировки не будут работать (они зависят от потока).

TL: DR;при вызове метода jni из java я обращаюсь только к переменной env и второй переменной jobject в потоке рендеринга, и нигде больше нигде, что до сих пор помогло решить мою проблему.

0 голосов
/ 10 августа 2011

С риском указать на чрезвычайно очевидное ... вы уверены, что не переполнены str?

char str[64];
sprintf(str, "%s/GameAssets", ROOTSTR);
...