请教Native Peer与Java Peer的定义、区分及相关示例
搞懂Java Peer和Native Peer:用代码实例说话
哈哈,这个概念刚接触确实容易懵,我用代码+大白话给你讲清楚,保证你秒懂!
先明确核心定义
- Java Peer:就是你写的普通Java对象,它是JVM里的「代言人」,负责和本地(Native)代码交互。它在JVM堆上分配,受垃圾回收器(GC)管理。
- Native Peer:是Java对象通过
native方法调用的本地系统资源/对象(比如C/C++里分配的内存、操作系统的文件句柄、网络套接字等)。这些东西不在JVM的管辖范围内,GC完全感知不到它们的存在——如果Java Peer被回收了,但没手动释放Native Peer,就会造成内存泄漏或者资源浪费。
用你提到的PrintHello类举例子
假设我们写一个PrintHello类,它需要调用本地代码操作文件资源。这里PrintHello的实例就是Java Peer,而本地代码里的文件句柄、自定义结构体就是Native Peer。
第一步:Java Peer代码(PrintHello类)
public class PrintHello { // 声明调用本地代码的方法 private native void nativePrint(); // 保存本地资源的句柄,方便后续释放 private long nativeHandle; // 加载本地库(编译后的C/C++动态库) static { System.loadLibrary("PrintHelloNative"); } // 构造方法:创建Java Peer的同时,初始化Native Peer public PrintHello() { this.nativeHandle = initNativePeer(); } // 本地方法:创建Native Peer(比如打开文件、分配本地内存) private native long initNativePeer(); // 终结器:当Java Peer被GC回收时,用来清理Native Peer @Override protected void finalize() throws Throwable { try { // 调用本地方法释放Native Peer资源 releaseNativePeer(nativeHandle); } finally { super.finalize(); } } // 本地方法:释放Native Peer资源 private native void releaseNativePeer(long handle); }
第二步:Native Peer对应的C代码
#include <jni.h> #include "PrintHello.h" #include <stdio.h> #include <stdlib.h> // 自定义的Native Peer结构体:持有一个文件句柄 typedef struct { FILE* logFile; } NativeHelloResource; // 初始化Native Peer:分配内存+打开文件 JNIEXPORT jlong JNICALL Java_PrintHello_initNativePeer(JNIEnv *env, jobject obj) { NativeHelloResource* nativeRes = (NativeHelloResource*)malloc(sizeof(NativeHelloResource)); // 打开一个日志文件,这个文件句柄就是Native Peer的一部分 nativeRes->logFile = fopen("native_log.txt", "w"); return (jlong)nativeRes; } // 调用本地方法打印内容,操作Native Peer JNIEXPORT void JNICALL Java_PrintHello_nativePrint(JNIEnv *env, jobject obj, jlong handle) { NativeHelloResource* res = (NativeHelloResource*)handle; fprintf(res->logFile, "Hello from Native World!\n"); } // 释放Native Peer:关闭文件+释放内存 JNIEXPORT void JNICALL Java_PrintHello_releaseNativePeer(JNIEnv *env, jobject obj, jlong handle) { NativeHelloResource* res = (NativeHelloResource*)handle; fclose(res->logFile); free(res); // 释放本地分配的内存 }
回答你的具体疑问
示例中的Java类PrintHello还是使用PrintHello的其他类?
答案是PrintHello本身就是Java Peer!使用它的其他类只是调用者,不是Java Peer。Java Peer是那个直接和Native层绑定、持有Native资源句柄的Java对象。Native Peer与Java Peer分别指哪部分?
还是拿上面的例子说:- Java Peer:就是你在代码中创建的
PrintHello实例,比如PrintHello hello = new PrintHello();里的hello对象,它在JVM堆里,GC能找到它并回收。 - Native Peer:就是C代码里的
NativeHelloResource结构体实例,还有它持有的FILE*文件句柄——这些都是在JVM之外的本地资源,GC完全看不到,必须手动调用releaseNativePeer方法释放。
- Java Peer:就是你在代码中创建的
为什么需要finalize?
因为如果Java Peer被GC回收了,但我们没手动调用releaseNativePeer,那Native Peer就会一直留在内存/系统资源里,造成泄漏。而finalize方法就是JVM在回收Java Peer之前给我们的最后机会,用来清理这些GC管不到的Native Peer。
内容的提问来源于stack exchange,提问作者SMUsamaShah
相关产品推荐
相关产品推荐

