Android JNI local reference table overflow: local reference table overflow (max = 512), androidjni

Source: Internet
Author: User

Android JNI local reference table overflow: local reference table overflow (max = 512), androidjni

Reprinted please indicate the source: http://blog.csdn.net/xyang81/article/details/44873769

In JNI/NDK Development Guide (10) -- JNI local reference, global reference, and weak global reference, this article details how to use three references in JNI, differences, application scenarios, and development considerations. Because they are all theories, they may not be deeply impressed after reading them, because they are prone to errors during development. Therefore, this article uses an example to illustrate the problems caused by improper reference, so as to attract everyone's attention to this knowledge point.

First, create an Android project, and put a text box and a button on the main interface. The text box is used to receive the number N of local references created. click the button to obtain the number in the text box, then, call the native method to create a string array of N in the local code, return to the Java layer, and output it to the console.

The interface is as follows:


Activity_main.xml is as follows:

<LinearLayout xmlns: android = "http://schemas.android.com/apk/res/android" xmlns: tools = "http://schemas.android.com/tools" android: layout_width = "match_parent" android: layout_height = "match_parent" android: orientation = "horizontal" android: padding = "5dip"> <EditText android: id = "@ + id/str_count" android: layout_width = "0dip" android: layout_height = "wrap_content" android: layout_weight = "1" android: inputType = "numberDecimal"/> <Button android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_toRightOf = "@ id/str_count" android: onClick = "onTestLocalRefOverflow" android: text = "partial reference table overflow test"/> </LinearLayout>
Declare the native method and initialize View in MainActivity
Package com. example. jni; import android. app. activity; import android. OS. bundle; import android. view. view; import android. widget. editText; public class MainActivity extends Activity {// returns an array of strings with the same count samples and identifies them with numbers, such as sample1, sample2... public native String [] getStrings (int count, String sample); EditText mEditText; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInsta NceState); setContentView (R. layout. activity_main); mEditText = (EditText) findViewById (R. id. str_count);} public void onTestLocalRefOverflow (View view) {String [] strings = getStrings (Integer. parseInt (mEditText. getText (). toString (), "I Love You % d Year !!! "); For (String string: strings) {System. out. println (string) ;}static {System. loadLibrary (" local_ref_overflow_test ");}}

The code in Java is relatively simple. MainActivity declares a native method getStrings, which is used to call the local function. The onTestLocalRefOverflow method is the Click Event of the button on the main interface, and the getStrings method is called after the button is clicked, input the number and content of the string, and then return N arrays of the same string length.
Next, create a jni directory under the project and create Android. mk, Application. mk and local_ref_overflow_test.c files, Where Android. mk is the description file of C/C ++ source code automatically compiled and packaged by the NDK compiling system. Application. mk describes some Parameter options during NDK compilation, such as C/C ++ precompiled macros and CPU architecture. (This article will be detailed later) local_ref_overflow_test.c is the C code for implementing the getStrings local method in MainActivity.
The content of the Android. mk file is as follows:

LOCAL_PATH: = $ (call my-dir) include $ (CLEAR_VARS) # Clear the environment variable LOCAL_MODULE: = local_ref_overflow_test # so file name, without adding the lib prefix and. so suffix LOCAL_SRC_FILES: = local_ref_overflow_test.c # C source file LOCAL_LDLIBS: =-llog # Link Log Module include $ (BUILD_SHARED_LIBRARY) # compile the source file into a shared library

The content of the Application. mk file is as follows:

APP_ABI: = armeabi armeabi-v7a # specify the type of the compiled CPU architecture

Local_ref_overflow_test.cThe file content is as follows:

# Include <jni. h> # include <stdlib. h> # include <stdio. h> # include <string. h> # include <android/log. h> # define LOG_TAG "MainActivity" # define LOG_ I (...) _ android_log_print (ANDROID_LOG_INFO, LOG_TAG, _ VA_ARGS _) # define LOG_E (...) _ android_log_print (ANDROID_LOG_ERROR, LOG_TAG, _ VA_ARGS _) # ifdef _ prop "C" {# define getStrings (JNIEnv * env, jobject obj, jint count, jstring sample) {job JectArray str_array = NULL; jclass cls_string = NULL; jmethodID mid_string_init; jobject obj_str = NULL; const char * c_str_sample = NULL; char buff [256]; int I; // ensure that at least three local references (str_array, cls_string, obj_str) if (* env)-> EnsureLocalCapacity (env, 3) can be created )! = JNI_ OK) {return NULL;} c_str_sample = (* env)-> GetStringUTFChars (env, sample, NULL); if (c_str_sample = NULL) {return NULL ;} cls_string = (* env)-> FindClass (env, "java/lang/String"); if (cls_string = NULL) {return NULL ;} // obtain the String construction method mid_string_init = (* env)-> GetMethodID (env, cls_string, "<init>", "() V "); if (mid_string_init = NULL) {(* env)-> DeleteLocalRef (env, cls_string); return NULL ;} Obj_str = (* env)-> NewObject (env, cls_string, mid_string_init); if (obj_str = NULL) {(* env)-> DeleteLocalRef (env, cls_string ); return NULL;} // create a string array str_array = (* env)-> NewObjectArray (env, count, cls_string, obj_str); if (str_array = NULL) {(* env)-> DeleteLocalRef (env, cls_string); (* env)-> DeleteLocalRef (env, obj_str); return NULL ;} // assign a value for (I = 0; I <count; ++ I) {memset (buff, 0, sizeof (buff); // The first buffer sprintf (buff, c_str_sample, I); jstring newStr = (* env)-> NewStringUTF (env, buff ); (* env)-> SetObjectArrayElement (env, str_array, I, newStr);} // release the memory occupied by the template string (* env)-> ReleaseStringUTFChars (env, sample, c_str_sample); // release the resources occupied by local references (* env)-> DeleteLocalRef (env, cls_string); (* env)-> DeleteLocalRef (env, obj_str ); return str_array;} const JNINativeMethod g_methods [] = {"ge TStrings "," (ILjava/lang/String;) [Ljava/lang/String; ", (void *) getStrings }}; static jclass g_cls_MainActivity = NULL; JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved) {LOG_ I ("JNI_OnLoad method call begin"); JNIEnv * env = NULL; jclass cls = NULL; if (* vm)-> GetEnv (vm, (void **) & env, JNI_VERSION_1_6 )! = JNI_ OK) {return JNI_ERR;} // find the local method Class to be loaded reference cls = (* env)-> FindClass (env, "com/example/jni/MainActivity"); if (cls = NULL) {return JNI_ERR;} // cache class references to global variables g_cls_MainActivity = (* env) -> NewWeakGlobalRef (env, cls); (* env)-> DeleteLocalRef (env, cls ); // It is a good habit to manually delete a local reference. // bind the native method in java with the local function (* env)-> RegisterNatives (env, g_cls_MainActivity, g_methods, sizeof (g_methods) /sizeof (g_methods [0]); LOG_ I ("JNI_OnLoad method call end"); return jni_version_00006;} JNIEXPORT void JNICALL JNI_OnUnload (JavaVM * vm, void * reserved) {LOG_ I ("JNI_OnUnload method call begin"); JNIEnv * env = NULL; if (* vm)-> GetEnv (vm, (void **) & env, JNI_VERSION_1_6 )! = JNI_ OK) {return;} (* env)-> UnregisterNatives (env, g_cls_MainActivity); // unregister when so is uninstalled (* env)-> DeleteWeakGlobalRef (env, g_cls_MainActivity);} # ifdef _ cplusplus} # endif

If you have read this article, several functions of the above local code may not have been seen. The following is a brief description, which will be described in detail later. WhereJNI_OnLoadIt is the callback function when the Java layer calls the System. loadLibrary method to load the Shared Library to the virtual machine. It is suitable for some initialization processing here.JNI_OnUnloadA function is called back by a virtual machine when the shared library is detached. This function is suitable for processing resource release and memory recovery. 104th rowsRegisterNativesFunctions are used to bind local functions with the native method of Java. In this example, instead of using the javah command to generate the header file declarationRegisterNativesThe function binds the getStrings native method in Java with the local function getStrings. Function search can also be implemented, and the efficiency is higher.JNINativeMethodIt is a data structure used to describe a method name, function signature, and function pointer information. It is used to bind the ing between a local function and a Java native method. As follows:

Typedef struct {char * name; // function name char * signature; // function signature void * fnPtr; // function pointer} JNINativeMethod;

Note:void *fnPtrNote that the first parameter of the local function must be JNIEnv *,Second ParameterIf it is an instance method, it is jobject, the static method is jclass, and the following is the native method parameter in Java. For example, the native method getStrings declared in MainActivity in the previous example:public native String[] getStrings(int count, String sample);Corresponding local FunctionjobjectArray getStrings(JNIEnv *env, jobject obj, jint count, jstring sample).

getStringsI will not introduce the code in detail, that is, the function of creating a string array, which has been mentioned many times in previous articles. Now, read the implementation of this function carefully to see if it can be found out which would cause local reference table overflow. If you run the program now and enter a value greater than 501 in the text box, you will see a local reference table overflow and crash. As shown in:

At this time, you may think of what you learned using the previous article.EnsureLocalCapacityOrPushLocalFrame/PopLocalFrameInterface to expand the number of local references. For example, change row 25thif ((*env)->EnsureLocalCapacity(env, count + 3) != JNI_OK)To ensure that the function can create count + 3 numbers of references (here 3 refers to str_array, cls_string and obj_str ). Unfortunately,EnsureLocalCapacityIt will try to apply for a specified number of local references, but it may not be successful because the local references are created in the stack, if the memory space requested by reference of this order of magnitude exceeds the maximum memory space range of the stack, it will cause memory overflow. The result is shown in:

Therefore, in a local method, if a large number of local references are used but not released in time, the program may crash at any time. In the 63 rows in the preceding example, each traversal creates a new string and returns a local reference pointing to the string. After 64 is used up, it is ignored, in this case, when a large array is created, the local referenced table is filled up, resulting in a reference table overflow. According to the test, the maximum size of a local reference table in Android is 512 by default. This is implemented by a virtual machine and cannot be modified in the program. I think you should know how to fix this problem. Yes, callDeleteLocalRefDelete it. The modified code is as follows:

// Assign a value for (I = 0; I <count; ++ I) {memset (buff, 0, sizeof (buff) to each element in the array )); // initialize the buffer sprintf (buff, c_str_sample, I); jstring newStr = (* env)-> NewStringUTF (env, buff); (* env)-> SetObjectArrayElement (env, str_array, I, newStr); (* env)-> DeleteLocalRef (env, newStr); // Warning: if you do not manually release a local reference, it is likely that the local reference table will overflow}

After the modification, there is no problem with the size of the string array you have created. Of course, it cannot exceed the physical memory size! Because the memory allocated to the objects created in Java is all stored in the heap space. The following code creates a string array of 0.5 million characters to verify the verification, as shown in:

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.