Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please document that attach_current_thread_permanently() prevents automatic de-allocation of JNI local references #173

Open
wuwbobo2021 opened this issue Nov 16, 2024 · 0 comments

Comments

@wuwbobo2021
Copy link

I had encountered a memory leak problem while debugging the initial version of android-usbser-rs. A loop polling for USB transfer data causes the problem, and it crashed on older Android versions (< 8.0).

I did an experiement and realized that attach_current_thread_permanently() prevents automatic de-allocation of JNI local references, unless making use of local frames or the AutoLocal wrapper. Is there a solution with better performance?

Test program:

[package]
name = "android-simple-test"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
jni = "0.21"
ndk-context = "0.1"
android-activity = { version = "0.6", features = ["native-activity"] }

[lib]
name = "android_simple_test"
crate-type = ["cdylib"]
path = "main.rs"

[package.metadata.android]
package = "com.example.android_simple_test"
build_targets = [ "aarch64-linux-android" ]

[package.metadata.android.sdk]
min_sdk_version = 16
target_sdk_version = 30
#[no_mangle]
fn android_main(_: android_activity::AndroidApp) {
    let mut i: i32 = 0;
    loop {
        let _ = with_jni_env_ctx(|env, _| {
            let _ = env.new_string(format!("test {}", i))
                // .map(|o| env.auto_local(o))
                .unwrap();
            Ok(())
        });
        i = i.wrapping_add(1);
        if i == 1000_000 {
            println!("Not crashed");
        }
    }
}

use jni::errors::Error;
fn with_jni_env_ctx<R>(
    f: impl FnOnce(&mut jni::JNIEnv, &jni::objects::JObject<'static>) -> Result<R, Error>,
) -> Result<R, Error> {
    let ctx = ndk_context::android_context();
    let jvm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }?;
    let context = unsafe { jni::objects::JObject::from_raw(ctx.context().cast()) };
    let mut env = jvm.attach_current_thread()?;
    f(&mut env, &context)
}

It causes memory leak, and crashes on older Android versions:

11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): local reference table overflow (max=512)
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115] local reference table dump:
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]   Last 10 entries (of 512):
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       511: 0x12d511a0 java.lang.String "test 511"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       510: 0x12d51180 java.lang.String "test 510"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       509: 0x12d51160 java.lang.String "test 509"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       508: 0x12d51140 java.lang.String "test 508"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       507: 0x12d51120 java.lang.String "test 507"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       506: 0x12d51100 java.lang.String "test 506"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       505: 0x12d510e0 java.lang.String "test 505"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       504: 0x12d510c0 java.lang.String "test 504"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       503: 0x12d510a0 java.lang.String "test 503"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       502: 0x12d51080 java.lang.String "test 502"
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]   Summary:
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115]       512 of java.lang.String (512 unique instances)
11-16 01:49:21.761 16408 16422 F art     : art/runtime/indirect_reference_table.cc:115] 
11-16 01:49:21.765 16408 16421 I RustStdoutStderr: referenceTable GDEF length=814 1
11-16 01:49:21.765 16408 16421 I RustStdoutStderr: referenceTable GSUB length=11364 1
11-16 01:49:21.765 16408 16421 I RustStdoutStderr: referenceTable GPOS length=47302 1
11-16 01:49:21.778   856  1849 D audio_hw_primary: start_output_stream: exit
11-16 01:49:21.813 16408 16422 F art     : art/runtime/barrier.cc:90] Check failed: count_ == 0 (count_=-1, 0=0) Attempted to destroy barrier with non zero count
11-16 01:49:21.813 16408 16422 F art     : art/runtime/runtime.cc:366] Runtime aborting --- recursively, so no thread-specific detail!
11-16 01:49:21.813 16408 16422 F art     : art/runtime/runtime.cc:366] 
--------- beginning of crash
11-16 01:49:21.813 16408 16422 F libc    : Fatal signal 6 (SIGABRT), code -6 in tid 16422 (android_main)

Put the loop in another thread, do not attach it to the JVM permanantly, then you'll not have this problem.

PS: would you like to check this issue (not important): mzdk100/droid-wrap#2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant