{"action":"created","issue":{"url":"https://api.github.com/repos/realm/realm-java/issues/2100","labels_url":"https://api.github.com/repos/realm/realm-java/issues/2100/labels{/name}","comments_url":"https://api.github.com/repos/realm/realm-java/issues/2100/comments","events_url":"https://api.github.com/repos/realm/realm-java/issues/2100/events","html_url":"https://github.com/realm/realm-java/issues/2100","id":127128426,"number":2100,"title":"Apparent memory leak with query on background Looper thread","user":{"login":"whoney","id":2995524,"avatar_url":"https://avatars.githubusercontent.com/u/2995524?v=3","gravatar_id":"","url":"https://api.github.com/users/whoney","html_url":"https://github.com/whoney","followers_url":"https://api.github.com/users/whoney/followers","following_url":"https://api.github.com/users/whoney/following{/other_user}","gists_url":"https://api.github.com/users/whoney/gists{/gist_id}","starred_url":"https://api.github.com/users/whoney/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/whoney/subscriptions","organizations_url":"https://api.github.com/users/whoney/orgs","repos_url":"https://api.github.com/users/whoney/repos","events_url":"https://api.github.com/users/whoney/events{/privacy}","received_events_url":"https://api.github.com/users/whoney/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/realm/realm-java/labels/Help","name":"Help","color":"cc317c"},{"url":"https://api.github.com/repos/realm/realm-java/labels/Pending","name":"Pending","color":"ededed"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2016-01-17T22:15:24Z","updated_at":"2016-01-19T05:19:09Z","closed_at":null,"body":"When a query is executed on a background thread with associated Looper, in a usual way like:\r\n\r\n```java\r\nRealmResults<> results = realm.where (Something.class).....findAll ();\r\n```\r\n\r\nRealm will retain a reference to every RealmObject in the result set, in the order to (possibly) update the object when a change happens to the underlying realm - which is correct behavior.\r\n\r\nHowever, there is no such method as RealmResults.close or anything similar. If we reuse the same Realm instance and run the query again, producing new RealmResults and dropping the reference to the old one, strong references to the RealmObjects seem to be retained and the heap grows uncontrollably, eventually leading to OOM - in my specific case, with a dataset of about 30k objects, it is enough to rerun the query only about 10-20 times before hitting OOM (Realm 0.87.2, on Android emulator API 23).\r\n\r\nI've tried both asynchronous queries with listeners (detaching them of course) and synchronous, with the same OOM result. So far the only way to avoid OOM in my specific case is to create a new Realm instance before running the query and closing it after retrieving the results. It works acceptably but comes with a performance impact due to creating and closing Realm instance; also, it is not possible to use Realm's auto-update feature with such workaround.\r\n\r\nHow to reproduce:\r\n\r\n1. Create a reasonably large dataset (30k simple objects were enough in my case, no relationships etc);\r\n2. Create a background thread with an associated Looper;\r\n3. Create Realm instance in the background thread;\r\n4. Periodically (e.g. on a button press) run a query against this dataset in the background thread (passing a message to the thread via Handler to initiate the query);\r\n5. Feed the results to the UI thread by using Realm.copyFromRealm on the RealmResults, but don't close the Realm instance;\r\n6. Wait for OOM.\r\n\r\nThere seems to be no difference whether the query is synchronous or asynchronous. Just before OOM, heap dump shows an excessive amount of RealmObjects being referred to by HandlerCallback associated with the background thread as described above. At the same time, there are no stale instances of RealmResults (other than the \"last\" one), indicating that they're properly collected by GC, while RealmObjects are not.\r\n\r\nAm I missing something obvious or is this indeed a bug/unexpected behavior?\r\n"},"comment":{"url":"https://api.github.com/repos/realm/realm-java/issues/comments/172741091","html_url":"https://github.com/realm/realm-java/issues/2100#issuecomment-172741091","issue_url":"https://api.github.com/repos/realm/realm-java/issues/2100","id":172741091,"user":{"login":"beeender","id":449296,"avatar_url":"https://avatars.githubusercontent.com/u/449296?v=3","gravatar_id":"","url":"https://api.github.com/users/beeender","html_url":"https://github.com/beeender","followers_url":"https://api.github.com/users/beeender/followers","following_url":"https://api.github.com/users/beeender/following{/other_user}","gists_url":"https://api.github.com/users/beeender/gists{/gist_id}","starred_url":"https://api.github.com/users/beeender/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/beeender/subscriptions","organizations_url":"https://api.github.com/users/beeender/orgs","repos_url":"https://api.github.com/users/beeender/repos","events_url":"https://api.github.com/users/beeender/events{/privacy}","received_events_url":"https://api.github.com/users/beeender/received_events","type":"User","site_admin":false},"created_at":"2016-01-19T05:19:09Z","updated_at":"2016-01-19T05:19:09Z","body":"@whoney How is your minimal example going on? Or is it possible that just share some code piece for below:\r\n\r\n> Periodically (e.g. on a button press) run a query against this dataset in the background thread (passing a message to the thread via Handler to initiate the query);\r\n> Feed the results to the UI thread by using Realm.copyFromRealm on the RealmResults, but don't close the Realm instance;\r\n\r\nThe data structure of your model object doesn't matter. I want to have a look at the logic of \"query\", \"usage of RealmResults\"."}}