如何用SWIG 4.1为指针引用生成JNI包装器并解决内存崩溃问题
问题分析与解决方案
问题根源
SWIG默认对C指针引用(Butler*&)的类型映射未正确处理引用语义,导致Java端传递的代理对象无法关联到有效的C实例,进而出现实例未正确创建、内存崩溃等问题。
核心修复:自定义SWIG Typemap
无需修改C++接口,通过添加以下SWIG类型映射来修正指针引用的JNI转换逻辑:
完整SWIG接口配置示例
// 先包含目标类的头文件 %include "Butler.h" %include "ButlerService.h" // 处理Butler*&作为输入参数(对应addButler方法的参数) %typemap(jni) Butler*& "jlong" %typemap(javain) Butler*& "$javainput.getCPtr()" %typemap(in) Butler*& { // 将JNI层传递的指针值转换为C++指针引用 Butler* temp_ptr = reinterpret_cast<Butler*>(static_cast<intptr_t>($input)); $1 = &temp_ptr; } // 处理Butler*&作为返回值(对应getButler方法) %typemap(out) Butler*& { // 将C++指针引用指向的实例包装为Java代理对象 $result = new Butler(reinterpret_cast<jlong>(*$1), true); } // 确保Butler类的代理对象正确继承SWIG的指针管理类 %typemap(javabase) Butler "SWIGTYPE_p_Butler"
各Typemap作用说明
%typemap(jni):指定JNI层用jlong存储C++指针值(Java无原生指针类型,用长整型模拟)。%typemap(javain):Java端调用时,通过SWIG自动生成的getCPtr()方法获取代理对象对应的C++指针,传递给JNI层。%typemap(in):在JNI层将jlong转换为C指针引用,确保C方法接收到有效的实例指针引用。%typemap(out):将C++返回的指针引用指向的实例,包装为Java代理对象,第二个参数true表示让Java对象托管该实例的内存(可根据实际内存管理需求调整)。
额外注意事项
- 确保Butler类的SWIG包装未禁用默认构造函数:若Java端创建Butler实例,SWIG默认生成的构造函数会同步创建对应的C++实例,除非手动添加了
%nodefaultctor。 - 内存生命周期管理:如果C端需要长期持有Butler实例,需避免Java端过早回收代理对象导致C指针悬空,可通过
%newobject标记或手动控制对象生命周期。
内容的提问来源于stack exchange,提问作者Sahaj
相关产品推荐
相关产品推荐

