alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (README.JNI)

This example Java source code file (README.JNI) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

all, awt, awtcomponent\:\:measurelistitem, however, java, jni, measureitemstruct, not, poplocalframe, pushlocalframe, the, this, use

The README.JNI Java example source code

[sl@eng 97/07/24]

All the free-standing functions (those that are not JNI native
methods) must not leak local references.  Local references are
automatically freed when the native method returns to Java. However,
the free-standing functions are called from the event loop that never
returns to Java. If these functions do not clean up the local
references they create, the Java objects corresponding to the local
references will never be garbage collected.

This is caused by the fact that JNI does not clean up local refs 
until control returns to Java. However, this problem is somewhat
unique to AWT code because AWT code has long-running native methods
that never return.

Local refs may be cleaned up manually *before* control returns to 
Java in one of the following two ways:

1. Use EnsureLocalCapacity at the beginning of the function to make
sure the VM has enough memory to create the number of JNI local refs
needed in the function. Use DeleteLocalRef to clean up any local ref
created inside the function that are not returned as the result. For
example:

  void AwtComponent::MeasureListItem(JNIEnv *env, 
				     MEASUREITEMSTRUCT far& measureInfo)
  {
      if (env->EnsureLocalCapacity(1) < 0) {
	  return;
      }
      jobject dimension = PreferredItemSize(env);

      ... /* Use dimension */

      env->DeleteLocalRef(dimension);
  }

2. Use PushLocalFrame and PopLocalFrame to start a new local reference
frame. All the local refs created in the new frame will be automatically
freed when PopLocalFrame is called. For example, the above function can be
rewritten as follows:

  void AwtComponent::MeasureListItem(JNIEnv *env, 
				     MEASUREITEMSTRUCT far& measureInfo)
  {
      if (env->PushLocalFrame(1) < 0) {
	  return;
      }
      jobject dimension = PreferredItemSize(env);

      ... /* Use dimension */

      env->PopLocalFrame(NULL);
  }

The second approach is easier to use when there are multiple local refs 
to manage. The first approach is more efficient when the function only 
needs to create a small number (3 or less) of local refs.

Pay special attention to local refs created inside a loop. They must be
deleted after every iteration, otherwise they accumulate very quickly:

int AwtFont::getFontDescriptorNumber(JNIEnv *env, jobject font,
				     jobject fontDescriptor)
{
    ... /* other stuff */

    jarray array = ...

    for (i = 0; i < num; i++){
	refFontDescriptor = env->GetObjectArrayElement(array, i);
	if (env->IsSameObject(refFontDescriptor, fontDescriptor)) {
	    env->DeleteLocalRef(refFontDescriptor);
	    env->DeleteLocalRef(array);
	    return i;
	}
	env->DeleteLocalRef(refFontDescriptor);
    }
    env->DeleteLocalRef(array);
    return 0;	// Not found.  Use default.
}

Note that we must make sure the local refs are cleaned up at every possible
return branch. To reduce code duplication, many AWT functions use "goto"
to jump to a common set of cleanup statements.

Even if we use PushLocalFrame, we must still delete the local refs created
in the loop:

    if (env->PushLocalFrame(2) < 0)
	return 0;
    jarray array = ...
    for (i = 0; i < num; i++){
	refFontDescriptor = env->GetObjectArrayElement(array, i);
	if (env->IsSameObject(refFontDescriptor, fontDescriptor)) {
	    env->PopLocalFrame(NULL);
	    return i;
	}
	env->DeleteLocalRef(refFontDescriptor);
    }
    env->PopLocalFrame(NULL);
    return 0;	// Not found.  Use default.

unless we ensure that we have space for all possible local refs we are 
going to create inside the loop (note the different argument passed 
to PushLocalFrame):

// Maximum number of local refs we can create in this code segment is
// num + 1.
    if (env->PushLocalFrame(num + 1) < 0)
	return 0;
    jarray array = ...
    for (i = 0; i < num; i++){
	refFontDescriptor = env->GetObjectArrayElement(array, i);
	if (env->IsSameObject(refFontDescriptor, fontDescriptor)) {
	    env->PopLocalFrame(NULL);
	    return i;
	}
// no longer necessary. env->DeleteLocalRef(refFontDescriptor);
    }
    env->PopLocalFrame(NULL);
    return 0;	// Not found.  Use default.

THINGS TO DO:

    1. Investigate another possibility of dealing with local refs. Instead
    of making sure every free-standing function does not leak local refs,
    we could alternatively create a new local ref frame for each invocation
    of callback functions. All local refs created during the execution of 
    the callback will then be automatically freed.

    2. Handle exceptions properly. The current code lacks error checking
    and recovery. This leads to random runtime crashes.


Other Java examples (source code examples)

Here is a short list of links related to this Java README.JNI source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.