在JNI编程中避免内存泄漏(二),jni泄漏
在JNI编程中避免内存泄漏(二),jni泄漏
JAVA 中的内存泄漏
JAVA 编程中的内存泄漏,从泄漏的内存位置角度可以分为两种:JVM 中 Java Heap 的内存泄漏;JVM 内存中native memory 的内存泄漏。
Java Heap 的内存泄漏
Java 对象存储在 JVM 进程空间中的 Java Heap 中,Java Heap 可以在 JVM 运行过程中动态变化。如果Java 对象越来越多,占据 Java Heap 的空间也越来越大,JVM 会在运行时扩充 Java Heap 的容量。如果 JavaHeap 容量扩充到上限,并且在 GC 后仍然没有足够空间分配新的 Java 对象,便会抛出 out of memory 异常,导致JVM 进程崩溃。
Java Heap 中 out of memory 异常的出现有两种原因——①程序过于庞大,致使过多 Java对象的同时存在;②程序编写的错误导致 Java Heap 内存泄漏。
多种原因可能导致 Java Heap 内存泄漏。JNI 编程错误也可能导致 Java Heap 的内存泄漏。
JVM 中 native memory 的内存泄漏
从操作系统角度看,JVM在运行时和其它进程没有本质区别。在系统级别上,它们具有同样的调度机制,同样的内存分配方式,同样的内存格局。
JVM 进程空间中,Java Heap 以外的内存空间称为 JVM 的 native memory。进程的很多资源都是存储在JVM 的 native memory 中,例如载入的代码映像,线程的堆栈,线程的管理控制块,JVM 的静态数据、全局数据等等。也包括JNI 程序中 native code 分配到的资源。
在 JVM 运行中,多数进程资源从 native memory 中动态分配。当越来越多的资源在 native memory中分配,占据越来越多 native memory 空间并且达到 native memory 上限时,JVM 会抛出异常,使 JVM进程异常退出。而此时 Java Heap 往往还没有达到上限。
多种原因可能导致 JVM 的 native memory 内存泄漏。例如 JVM在运行中过多的线程被创建,并且在同时运行。JVM 为线程分配的资源就可能耗尽 native memory 的容量。
JNI 编程错误也可能导致 native memory 的内存泄漏。对这个话题的讨论是本文的重点。
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 对象会一直存在 JavaHeap 中。程序员在使用 Global Reference 时,需要仔细维护对 Global Reference的使用。如果一定要使用 Global Reference,务必确保在不用的时候删除。就像在 C 语言中,调用 malloc()动态分配一块内存之后,调用 free() 释放一样。否则,Global Reference 引用的 Java 对象将永远停留在Java Heap 中,造成 Java Heap 的内存泄漏。
相关文章
- 暂无相关文章
用户点评