You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请教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); // 释放本地分配的内存
}

回答你的具体疑问

  1. 示例中的Java类PrintHello还是使用PrintHello的其他类?
    答案是PrintHello本身就是Java Peer!使用它的其他类只是调用者,不是Java Peer。Java Peer是那个直接和Native层绑定、持有Native资源句柄的Java对象。

  2. Native Peer与Java Peer分别指哪部分?
    还是拿上面的例子说:

    • Java Peer:就是你在代码中创建的PrintHello实例,比如PrintHello hello = new PrintHello();里的hello对象,它在JVM堆里,GC能找到它并回收。
    • Native Peer:就是C代码里的NativeHelloResource结构体实例,还有它持有的FILE*文件句柄——这些都是在JVM之外的本地资源,GC完全看不到,必须手动调用releaseNativePeer方法释放。

为什么需要finalize?

因为如果Java Peer被GC回收了,但我们没手动调用releaseNativePeer,那Native Peer就会一直留在内存/系统资源里,造成泄漏。而finalize方法就是JVM在回收Java Peer之前给我们的最后机会,用来清理这些GC管不到的Native Peer。

内容的提问来源于stack exchange,提问作者SMUsamaShah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:20:02