Длинная история Java / Android / JNI ... У меня есть два класса, объект / класс, который я создал, называемый Packet, и интерфейс JNI для низкоуровневого кода C, который я написал.В одном классе я анализирую входящие пакеты и сохраняю их в ArrayList.Когда они "анализируются", вызывается функция Packet.dissect (), которая использует JNI для вызова C-кода более низкого уровня.Этот C-код выполняет функцию malloc () и возвращает указатель памяти на код 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 () для вызова функции C-кода JNI, передавая указатель, который освобождает память:
protected void finalize() throws Throwable {
try {
if(_dissection_ptr!=-1)
dissectCleanup(_dissection_ptr);
} finally {
super.finalize();
}
}
Отлично, это прекрасно работает ДО Я пытаюсь поделиться ArrayList со вторым классом.Для этого я использую Broadcast в 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 () ONCE для каждого пакета (когда оба классасчитается законченным с каждым пакетом).Это очень важно, иначе free () будет вызываться дважды по одному и тому же указателю (вызывая SEGFAULT).
Кажется, это происходит со мной.Как только второй класс получает ArrayList из широковещательной рассылки, он анализирует его и содержит несколько пакетов из списка.При этом существует другой объект / класс, который имеет член типа Packet. Если мне «нравится» пакет, я сохраняю его, выполняя:
other_object.pkt = pktFromList;
В конце концов этот метод, получивший Broadcast, возвращаети некоторые из Пакетов были "сохранены".Наконец, когда я нажимаю кнопку (несколько секунд спустя), 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
Итак, одно из двух предположений, которые яЯ делаю об объектах, которые передаются вокруг ложно.Кто-нибудь знает, что это может быть, и как я могу передать объекты более тщательно по ссылке, чтобы я мог очистить память должным образом?
Если вы сделали это так далеко через мой вопрос и поняли это, спасибо;)