做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉。因为我是学Java 开始的,所以对主动释放内存没多大概念(GC直接帮忙回收),后查询原因才知道是因为JNI 有些对象内存未释放引起。下面介绍下相关的资源释放。

JNI 编程实现了 native code 和 Java 程序的交互,因此 JNI 代码编程既遵循 native code 编程语言的编程规则,同时也遵守 JNI 编程的文档规范。在内存管理方面,native code 编程语言本身的内存管理机制依然要遵循,同时也要考虑 JNI 编程的内存管理。

本章简单概括 JNI 编程中显而易见的内存泄漏。从 native code 编程语言自身的内存管理,和 JNI 规范附加的内存管理两方面进行阐述。

Native Code 本身的内存泄漏

JNI 编程首先是一门具体的编程语言,或者 C 语言,或者 C++,或者汇编,或者其它 native 的编程语言。每门编程语言环境都实现了自身的内存管理机制。因此,JNI 程序开发者要遵循 native 语言本身的内存管理机制,避免造成内存泄漏。以 C 语言为例,当用 malloc() 在进程堆中动态分配内存时,JNI 程序在使用完后,应当调用 free() 将内存释放。总之,所有在 native 语言编程中应当注意的内存泄漏规则,在 JNI 编程中依然适应。

Native 语言本身引入的内存泄漏会造成 native memory 的内存,严重情况下会造成 native memory 的 out of memory。

Global Reference 引入的内存泄漏

JNI 编程还要同时遵循 JNI 的规范标准,JVM 附加了 JNI 编程特有的内存管理机制。

JNI 中的 Local Reference 只在 native method 执行时存在,当 native method 执行完后自动失效。这种自动失效,使得对 Local Reference 的使用相对简单,native method 执行完后,它们所引用的 Java 对象的 reference count 会相应减 1。不会造成 Java Heap 中 Java 对象的内存泄漏。

而 Global Reference 对 Java 对象的引用一直有效,因此它们引用的 Java 对象会一直存在 Java Heap 中。程序员在使用 Global Reference 时,需要仔细维护对 Global Reference 的使用。如果一定要使用 Global Reference,务必确保在不用的时候删除。就像在 C 语言中,调用 malloc() 动态分配一块内存之后,调用 free() 释放一样。否则,Global Reference 引用的 Java 对象将永远停留在 Java Heap 中,造成 Java Heap 的内存泄漏。

1、什么需要释放? 

什么需要什么呢 ? JNI 基本数据类型是不需要释放的 , 如 jint , jlong , jchar 等等 。 我们需要释放是引用数据类型,当然也包括数组家族。如:jstring ,jobject ,jobjectArray,jintArray 等等。

当然,大家可能经常忽略掉的是 jclass ,jmethodID , 这些也是需要释放的哦

2、如何去释放?

1)      释放String

jstring jstr = NULL;

char* cstr = NULL;

//调用方法

jstr = (*jniEnv)->CallObjectMethod(jniEnv, mPerson, getName);

cstr = (char*) (*jniEnv)->GetStringUTFChars(jniEnv,jstr, 0);

__android_log_print(ANDROID_LOG_INFO, "JNIMsg", "getName  ---- >  %s",cstr );

//释放资源

(*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, cstr);

(*jniEnv)->DeleteLocalRef(jniEnv, jstr);

2)      释放 类 、对象、方法

(*jniEnv)->DeleteLocalRef(jniEnv, XXX);

“XXX” 代表 引用对象

3)      释放 数组家族

jobjectArray arrays = NULL;

jclass jclsStr = NULL;

jclsStr = (*jniEnv)->FindClass(jniEnv, "java/lang/String");

arrays = (*jniEnv)->NewObjectArray(jniEnv, len, jclsStr, 0);

(*jniEnv)->DeleteLocalRef(jniEnv, jclsStr);  //释放String类

(*jniEnv)->DeleteLocalRef(jniEnv, arrays); //释放jobjectArray数组

native method 调用 DeleteLocalRef() 释放某个 JNI Local Reference 时,首先通过指针 p 定位相应的 Local Reference 在 Local Ref 表中的位置,然后从 Local Ref 表中删除该 Local Reference,也就取消了对相应 Java 对象的引用(Ref count 减 1)。

参考文章:在 JNI 编程中避免内存泄漏

本文出自 duicky博客 , 转载请注明出处  http://www.cnblogs.com/luxiaofeng54/archive/2011/08/21/2147822.html

基于 Android NDK 的学习之旅-----资源释放的更多相关文章

  1. 【转】基于 Android NDK 的学习之旅-----数据传输(引用数据类型)

    原文网址:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/20/2147086.html 基于 Android NDK 的学习之旅-----数据 ...

  2. 基于 Android NDK 的学习之旅-----环境搭建

    工欲善其事 必先利其器 , 下面介绍下 Eclipse SDK NDK Cygwin CDT 集成开发环境的搭建. 1.Android 开发环境搭建 Android开发环境搭建不是重点,相信看此文章的 ...

  3. 基于 Android NDK 的学习之旅-----序言

    前些日子做了个Android项目, 引擎层 用C的, 准备写这个系类的文章,借此跟朋友来分享下我NDK开放的经验以及自己知识的总结和备忘.希望能给需要这方面资料的朋友提供一定的帮助. 主要涉及到:   ...

  4. 基于 Android NDK 的学习之旅-----HelloWorld

    Hello World作为所有编程语言的起始阶段,占据着无法改变的地位,所有中/英/法/德/美……版本的编程教材中,hello world总是作为第一个TEST记录于书本之中,所有的编程第一步就在于此 ...

  5. 基于 Android NDK 的学习之旅-----JNI LOG 打印

    程序都是调出来的. 下面我介绍下JNI层的log打印方法的使用,类似与Android sdk提供的log 1.Android 应用层 MainActivity.java 主要功能代码 a)       ...

  6. 基于 Android NDK 的学习之旅-----数据传输(引用数据类型)

    接着上篇文章继续讲.主要关于引用类型的数据传输,本文将介绍字符串传输和自定义对象的传输. 1.主要流程 1.  String 字符串传输 a)         上层定义一个native的方法,需要一个 ...

  7. 基于 Android NDK 的学习之旅-----Java 调用C

    随便谈谈为什么要Java调用C 吧: 我认为: 1.  有些公司开发Android项目的时候, 许多组件功能可能是C中已经实现了,所以我们没必要同样的功能又在java中实现一遍.例如我之前做的一个项目 ...

  8. 基于 Android NDK 的学习之旅----- C调用Java

    许多成熟的C引擎要移植到Android 平台上使用 , 一般都会 提供 一些接口, 让Android sdk 和 jdk 实现. 下文将会介绍 C 如何 通过 JNI 层调用 Java 的静态和非静态 ...

  9. 基于 Android NDK 的学习之旅-----Android.mk 介绍

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

随机推荐

  1. Codeforces 451 E. Devu and Flowers(组合数学,数论,容斥原理)

    传送门 解题思路: 假如只有 s 束花束并且不考虑 f ,那么根据隔板法的可重复的情况时,这里的答案就是 假如说只有一个 f 受到限制,其不合法时一定是取了超过 f 的花束 那么根据组合数,我们仍然可 ...

  2. 使用JOTM实现分布式事务管理(多数据源)

    使用spring和hibernate可以很方便的实现一个数据源的事务管理,但是如果需要同时对多个数据源进行事务控制,并且不想使用重量级容器提供的机制的话,可以使用JOTM达到目的. JOTM的配置十分 ...

  3. Elasticsearch和MongoDB

    Elasticsearch和MongoDB分片及高可用对比 本文旨在对比Elasticsearch和MongoDB高可用和分片的实现机制. Elasticsearch ES天生就是分布式的,那她又是如 ...

  4. 右键菜单→新建→BAT 批处理文件

    目的:以前编写BAT,通常新建一个文本,然后另存为 .bat,比较麻烦,那么如何右键新建菜单里添加新建批处理文件呢? 代码如下: @echo offcd /d %temp%echo Windows R ...

  5. Impala基础认知与安装

    一.Impala简介 Cloudera Impala对你存储在Apache Hadoop在HDFS,HBase的数据提供直接查询互动的SQL.除了像Hive使用相同的统一存储平台,Impala也使用相 ...

  6. 【例题 7-7 UVA - 1354】Mobile Computing

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 秤砣都是在叶子节点. 可以把它看成一个二叉树. 则我们每次只需要选择任意两个"节点",让他们组成一棵二叉树就可以 ...

  7. Mrakdonw学习

    转载请注明出处:http://blog.csdn.net/cym492224103 什么是Mrakdown 为什么使用Mrakdown 怎样Mrakdown 字体 删除线 字体大小 引用 代码行代码块 ...

  8. CSS笔记 - fgm练习 2-10 - 提示框效果 (清除子元素浮动高度塌陷的影响)

    CSS清除浮动方法参考: https://blog.csdn.net/promiseCao/article/details/52771856 <style> *{ margin: 0; p ...

  9. jmeter--函数助手对话框之参数详解

    详解JMeter函数和变量 测试人员可以在JMeter的选项菜单中找到函数助手对话框("Function Helper"对话框),如图11-1所示. 图11-1 函数助手(Func ...

  10. 宏定义#define整理

    一.宏定义#define 优点:一方面可以节省程序的空间上的篇幅,另外,恰当地使用宏定义可提高程序的时间效率.代码可以写的通俗易懂.可以提高程序的清晰性.可读性,使于修改移植等. 缺点:宏定义的使用实 ...