长Java / Android / JNI的故事短...我有两个类,我创建一个对象/类称为数据包,以及一个JNI接口到我编写的低级C代码。在一个类中,我解析传入的数据包并将它们存储在ArrayList中。当它们被“解析”时,函数Packet.dissect()被调用,它使用JNI调用较低级别的C代码。这个C代码malloc()的某些内存,并将内存指针返回给将其存储在Packet对象的私有成员中的Java代码:

ArrayList _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中的Broadcast通过发送带有从第一个类的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);我认为这样做的真实情况是,列表中的每个Packet都通过引用该对象传递给第二个类。如果这是真的,那么无论两个类如何处理List和其中的对象,我保证垃圾回收器只会为每个数据包调用finalize()ONCE(当两个类都被认为已完成每个数据包时) 。这是非常重要的,或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所以,我正在做的关于传递的对象的两个假设之一是错误的。有谁知道它可能是什么,以及我如何通过引用更仔细地传递对象,以便我可以正确地清理内存?

如果你通过我的问题达到了这一点,并理解它,谢谢;)

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐