質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.62%

  • Android

    6394questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Kotlin

    295questions

    Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

JNI ERROR (app bug): weak global reference table overflow (max=51200)および弱参照について

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 302

shikasama

score 109

 前提・実現したいこと

測定機器とWi-fiで接続し、機器に表示される画像データを繰り返し取得し、ImageViewに表示するアプリを作成しています。

androidアプリのデバッグ中(10分くらい動作させっぱなし)に以下のエラーが発生しました。

JNI ERROR (app bug): weak global reference table overflow (max=51200)

JNIというものを初めて聞いたので調べ、JavaからCのライブラリを呼べる仕組みと認識しました。
個人で書いたコードではJNIを利用した覚えがないのでなぜエラーが起きたかわかりません。
そのため、コードのどこを調べていけばいいかもわかりません。

使用しているライブラリ中でJNIを利用しているとかでしょうか?

弱参照についても今調べていますが、まだわかっていません。
どういうところを疑えばいいか、エラーが起きる原因、解決方法などをご教授ください。

 発生している問題・エラーメッセージ

エラーログが長いので外部のテキスト共有サイトを利用します。
エラーログ

 該当のソースコード

どの箇所が影響しているかわかりませんでした。

追記
画像データの取得(ソケット通信)でスレッドを立てています。
参考になるかわかりませんが、いかにその部分を抜き出したコードを記載します。

波形データ取得部分

private fun getScreenImage() {
    isStop = false
    isTriggerStoped = false

    if(socketControl?.isConnect() == false) {
        // 未接続
        return
    }

    buttonSave.isEnabled = false

    Toast.makeText(applicationContext, getString(R.string.text_image_acquisition_start), Toast.LENGTH_SHORT).show()

    Thread(Runnable {
        while(!isStop) {
            Thread.sleep(0)
            waitForTrgStop()
            isTriggerStoped = false

            receiveBuff = null

            // 画像転送コマンド送信(受信データはBinary)
            var str = "(画像転送コマンド)"
            str += "PNG"

            Thread.sleep(10)
            socketControl?.sendCommand(str, true)

            var timeout = 500

            while (true) {
                try {
                    Thread.sleep(80)
                    if(timeout < 0) {
                        break
                    } else if(receiveBuff != null) {
                        imageData = receiveBuff?.copyOf()
                        receiveBuff = null
                        Thread.sleep(10)
                        break
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }

                timeout -= 100
            }

            if(timeout < 0) {
                continue
            }

            if(!checkBoxContinuousAcquisition.isChecked) {
                isStop = true
            }

            class Mythread : Thread() {
                override fun run() {
                    var bmp : Bitmap? = null
                    var imageSize = 0
                    if(imageData != null) {
                        imageSize = imageData?.size ?: 0
                        bmp = BitmapFactory.decodeByteArray(imageData, 0, imageSize)
                    }

                    if(imageSize == 0) {
                        Toast.makeText(applicationContext, getString(R.string.text_imageData_size_0), Toast.LENGTH_SHORT).show()
                        return
                    }

                    if(bbmp == null) {
                        Glide.with(applicationContext)
                                .load(bmp)
                                .into(imageViewWaveform)
                        bbmp = bmp
                    }
                    else {
                        requestOptions.placeholder(BitmapDrawable(resources,bmp))

                        Glide.with(applicationContext)
                                .load(bmp)
                                .apply(requestOptions)
                                .into(imageViewWaveform)
                        bbmp = bmp
                    }

                    if(isTriggerStoped) {
                        isTriggerStoped = false
                    }
                }
            }

            val myRun = Mythread()
            runOnUiThread(myRun)
            myRun.join()

            Thread.sleep(1)
        }

        if(checkBoxContinuousAcquisition.isChecked) {
            receiveBuff = null

            // 画像転送コマンド送信(受信データはBinary)
            var str = "(画像転送コマンド) "
            str += "PNG"

            Thread.sleep(100)
            socketControl?.sendCommand(str, true)

            while (true) {
                try {
                    Thread.sleep(100)
                    if(receiveBuff != null) {
                        imageData = receiveBuff?.copyOf()
                        receiveBuff = null
                        Thread.sleep(10)
                        break
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }

            class Mythread2 : Thread() {
                override fun run() {
                    var bmp : Bitmap? = null
                    var imageSize = 0
                    if(imageData != null) {
                        imageSize = imageData?.size ?: 0
                        bmp = BitmapFactory.decodeByteArray(imageData, 0, imageSize)
                    }

                    if(imageSize == 0) {
                        Toast.makeText(applicationContext, getString(R.string.text_imageData_size_0), Toast.LENGTH_SHORT).show()
                        return
                    }

                    if(bbmp == null) {
                        Glide.with(applicationContext)
                                .load(bmp)
                                .into(imageViewWaveform)
                        bbmp = bmp
                    }
                    else {
                        requestOptions.placeholder(BitmapDrawable(resources,bmp))

                        Glide.with(applicationContext)
                                .load(bmp)
                                .apply(requestOptions)
                                .into(imageViewWaveform)
                        bbmp = bmp
                    }


                    if(isTriggerStoped) {
                        isTriggerStoped = false
                    }
                }
            }

            val myRun2 = Mythread2()
            runOnUiThread(myRun2)
            myRun2.join()
        }

        class Mythread3 : Thread() {
            override fun run() {
                buttonGetScreenImage.isEnabled = true
                buttonSave.isEnabled = true
                Toast.makeText(applicationContext, getString(R.string.text_image_acquisition_stop), Toast.LENGTH_SHORT).show()
            }
        }

        val myRun3 = Mythread3()
        runOnUiThread(myRun3)
        myRun3.join()
    }).start()
}

ソケット通信でのデータ送信部分

fun sendCommand(sendStr: String, isBinaryReceive: Boolean): Boolean {
    if (this.socketClient?.isConnect() != true) {
        // 未接続
        return false
    }

    this.isBinary = isBinaryReceive
    this.receiveBuff = null
    this.receiveNum = 0
    val str = sendStr + "\r\n"
    val data = str.toByteArray(Charsets.UTF_8)
    this.socketClient?.sendThread(data)

    return true
}

fun sendThread(data : ByteArray) : Boolean {
    var result = false
    this.sendBuff = data
    try {
        thread {
            result = send(sendBuff)
        }.join()
    }
    catch (e : Exception) {
        Log.d("TCP/IP sendTh", e.toString())
    }
    return result
}

private fun send(data : ByteArray) : Boolean {
    var result = false

    try {
        output?.write(data, 0, data.size)
        output?.flush()
        result = true
    } catch (e : Exception) {
        Log.e("TCP/IP send", e.toString())
        return result
    }
    return result
}

 補足情報(FW/ツールのバージョンなど)

Android Studio3.0.1
kotlin 1.2.30

使用しているライブラリなど

  • org.jetbrains.kotlin:kotlin-stdlib-jdk7
  • com.android.support:support-v4:27.1.0
  • com.android.support.constraint:constraint-layout:1.0.2
  • com.android.support:design:27.1.0
  • junit:junit:4.12
  • com.android.support.test:runner:1.0.1
  • com.android.support.test.espresso:espresso-core:3.0.1
  • com.github.bumptech.glide:glide:4.6.1
  • com.github.bumptech.glide:compiler:4.6.1
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • kakajika

    2018/04/24 17:43

    JNIを直接触られていないのであれば、何らかの原因で解放漏れが起きている可能性が高そうです。エラーログを見ると落ちる直前に大量のthreadのインスタンスが生成されているようですが、これは意図する挙動ですか?

    キャンセル

  • shikasama

    2018/04/25 09:40

    画像データの取得とImageViewの更新でThreadを立てております。joinで待っているので問題ないかと思っていましたが、誤った認識なのでしょうか?また、デバッグだと再現して、ただの実行だと再現しませんでした。

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Android

    6394questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

  • Kotlin

    295questions

    Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。