💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
Java 2 SDK release 1.2提供了一组附加的函数用于管理局部引用的声明周期,这组函数是EnsureLocalCapacity, NewLocalRef, PushLocalFrame和PopLocalFrame. JNI规范规定虚拟机自动保证每个Native函数最多可以创建16个局部引用。经验来看这已经足够大多数使用场景了,但这不包含某些与Java虚拟机中对象有复杂交互的场景。如果存在创建额外的局部引用,Native代码需要发起一个EnsureLocalCapacity调用来保证足够数量的局部引用是可用的。如下例子中我们首先申请了足够个数的局部引用,然后在循环中创建局部引用: ~~~ /* The number of local references to be created is equal to the length of the array. */ if ((*env)->EnsureLocalCapacity(env, len)) < 0) { ... /* out of memory */ } for (int i = 0; i < len ; ++i ) { jstring jstr = (*env)->GetObjectArrayElement(env, arr, i); ... /* process jstr */ /* DeleteLocalRef is no longer necessary */ } ~~~ 当然,以上版本的代码比之前及时释放局部引用的代码消耗了更多的内存。 另一个选择是,使用Push/PopLocalFrame函数,它允许程序员创建嵌套的作用域。例如,我们可以重写代码如下: ~~~ #defind N_REFS ... /* the maximum number of local references used in each iteration */ for (int i = 0; i < len; ++i ) { if((*env)->PushLocalFrame(env, N_REFS) < 0) { ... /* out of memory */ } jstr = (*env)->GetObjectArrayElement(env, arr, i); ... /* process jstr */ (*env)->PopLocalFrame(env, NULL); } ~~~ PushLocalFrame为指定数目的据不宜用创建了一个新的作用域,PopLocalFrame则用于销毁当前最上层的作用域,释放在该作用域中的所有局部引用。 Native代码创建的局部引用可能会创建大于默认容量(16)或者在PushLocalFrame或者EnsureLocalCapacity调用时预留的大小。这个时候,虚拟机实现会尝试为局部引用分配更多的内存,但是,不保证内存分配操作一定会成功,如果分配内存失败,虚拟机就会退出,所以,你应当为局部引用预留足够多的内存并且尽早的释放它们来避免虚拟机出现这种异常状况。 Java 2 SDK release 1.2支持一个命令行选项 -verbose:jni,当这个选项开启的时候,虚拟机实现在超过预定限制容量的时候会输出局部引用报告。