长长的 Java/Android/JNI 简而言之……我有两个类,一个是我创建的名为 Packet 的对象/类,一个是我编写的低级 C 代码的 JNI 接口。在一类中,我解析传入的数据包并将它们存储在 ArrayList 中。当它们被“解析”时,会调用一个函数 Packet.dissect(),它使用 JNI 调用较低级别的 C 代码。此 C 代码 malloc() 的一些内存,并将内存指针返回到 Java 代码,Java 代码将其存储在 Packet 对象的私有成员中:
ArrayList<Packet> _scan_results;
...
// Loop and read headers and packets
while(true) {
Packet rpkt = new Packet(WTAP_ENCAP_IEEE_802_11_WLAN_RADIOTAP);
switch(_state) {
case IDLE:
break;
case SCANNING:
// rpkt.dissect() calls a JNI C-code function which allocates
// memory (malloc) and returns the pointer, which is stored in
// a private member of the Packet (rpkt._dissect_ptr).
rpkt.dissect();
if(rpkt.getField("wlan_mgt.fixed.beacon")!=null)
_scan_results.add(rpkt);
break;
}
}
现在,我想确保释放此内存,以免发生泄漏。因此,当垃圾收集器确定不再使用 Packet 对象时,我依靠 finalize() 调用 JNI C 代码函数,传递指针,从而释放内存:
protected void finalize() throws Throwable {
try {
if(_dissection_ptr!=-1)
dissectCleanup(_dissection_ptr);
} finally {
super.finalize();
}
}
太好了,这工作得很好,直到我尝试与第二类共享 ArrayList。为此,我在 Android 中使用广播,方法是将带有 ArrayList 列表的广播从第一类发送到第二类中的 BroadcastReceiver。这是从头等舱广播的地方:
// Now, send out a broadcast with the results
Intent i = new Intent();
i.setAction(WIFI_SCAN_RESULT);
i.putExtra("packets", _scan_results);
coexisyst.sendBroadcast(i);
我认为这样做的正确之处在于列表中的每个数据包都通过引用对象传递给第二个类。如果这是真的,那么无论这两个类对 List 和其中的对象做什么,我都保证垃圾收集器只会为每个数据包调用 finalize()一次(当两个类都被认为完成了每个数据包时) . 这非常重要,否则 free() 将在同一个指针上被调用两次(导致 SEGFAULT)。
这似乎发生在我身上。一旦第二个类从广播中接收到 ArrayList,它就会对其进行解析,并从列表中保存几个 Packet。这样做时,另一个对象/类有一个 Packet 类型的成员,如果我“喜欢”该数据包,我会通过以下方式保存它:
other_object.pkt = pktFromList;
最终这个接收广播的方法返回,并且一些数据包被“保留”。最后,当我单击一个按钮时(几秒钟后),原始类中的 ArrayList 被清除:
_scan_results.clear();
我假设即使在这里调用 clear() 时,如果第一个类“保留”了一些数据包,垃圾收集器也不会对它们调用 finalize()。唯一错误的方法是:(1)当广播被发送时,ArrayList 被复制而不是通过引用传递,或者(2)当数据包被“保留”在第二类,Packet 对象中时被复制而不是通过引用保存。
好吧,其中一个是错误的,因为 free() 偶尔会在同一块内存上调用两次。我看到它已分配(“新解剖:MEMORY_ADDRESS1 - IGNORE_THIS”),然后调用两个 finalize() 试图释放相同的内存地址:
INFO/Driver(6036): new dissection: 14825864 - 14825912
...
INFO/Driver(6036): received pointer to deallocate: 14825864
...
INFO/Driver(6036): received pointer to deallocate: 14825864
INFO/DEBUG(5946): signal 11 (SIGSEGV), fault addr 0000001c
因此,我对传递的对象所做的两个假设之一是错误的。有谁知道它可能是哪个,以及如何通过引用更仔细地传递对象,以便我可以正确清理内存?
如果您通过我的问题做到了这一点并理解它,谢谢;)