From 8cc3b58364efef6c671a5b53161ac73e3657114e Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Thu, 12 Nov 2015 08:40:58 +0900 Subject: [PATCH] Allow syncronizer to be GC-ed Proper fix for #1525. Using python's GC module, I've verified that the daemon, when running, now releases all verifiers, synchronizers and wallets - all the resources we care about releasing. --- lib/network.py | 7 +++++++ lib/synchronizer.py | 3 +++ lib/wallet.py | 5 ++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/network.py b/lib/network.py index 31201ad96..2054b856c 100644 --- a/lib/network.py +++ b/lib/network.py @@ -556,6 +556,13 @@ class Network(util.DaemonThread): message_id = self.queue_request(method, params) self.unanswered_requests[message_id] = method, params, callback + def unsubscribe(self, callback): + '''Unsubscribe a callback to free object references to enable GC.''' + # Note: we can't unsubscribe from the server, so if we receive + # subsequent notifications process_response() will emit a harmless + # "received unexpected notification" warning + self.subscriptions.pop(callback, None) + def connection_down(self, server): '''A connection to server either went down, or was never made. We distinguish by whether it is in self.interfaces.''' diff --git a/lib/synchronizer.py b/lib/synchronizer.py index ef4796b07..9b512671a 100644 --- a/lib/synchronizer.py +++ b/lib/synchronizer.py @@ -56,6 +56,9 @@ class Synchronizer(ThreadJob): return (not self.requested_tx and not self.requested_histories and not self.requested_addrs) + def release(self): + self.network.unsubscribe(self.addr_subscription_response) + def add(self, address): '''This can be called from the proxy or GUI threads.''' with self.lock: diff --git a/lib/wallet.py b/lib/wallet.py index 8a6fcfd1f..7cbc81a07 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -36,6 +36,7 @@ from transaction import Transaction from plugins import run_hook import bitcoin from synchronizer import Synchronizer +from verifier import SPV from mnemonic import Mnemonic import paymentrequest @@ -1128,7 +1129,6 @@ class Abstract_Wallet(PrintError): self.transactions.pop(tx_hash) def start_threads(self, network): - from verifier import SPV self.network = network if self.network is not None: self.prepare_for_verifier() @@ -1142,8 +1142,11 @@ class Abstract_Wallet(PrintError): def stop_threads(self): if self.network: self.network.remove_jobs([self.synchronizer, self.verifier]) + self.synchronizer.release() self.synchronizer = None self.verifier = None + # Now no references to the syncronizer or verifier + # remain so they will be GC-ed self.storage.put('stored_height', self.get_local_height(), True) def wait_until_synchronized(self, callback=None):