1

I was wondering if the observable is eligible to be garbage collected in this scenario:

fun getObservable() = Observable.interval(500, TimeUnit.Milliseconds)

fun main(args: Array<String>) {
    getObservable().subscribe { println(it) }

    //Just to be able to observe the output.
    Thread.sleep(20*1000)
}

It doesn't stop emitting. But I can't use it to be sure that it will not be GC'd after some time since it may just be that GC isn't triggering in this short span.

My guess is that it should be GC'd. We don't have a reference to the Observable returned from the getObservable() function since we can't access it anymore. Calling the function again will give a different new Observable. Since we can't reach the Observable itself, the rest of the objects are also unreachable. So, I think all of this can be garbage collected at any random time.

Some of my code in an Android App uses somewhat similar code. And it is an Observable that I hope will last as long as the Application. Since, GC will collect any garbage, I don't want my Observable to be GC'd in the middle of my app. So, please keep that in mind that I'm not looking for answers telling me whether it will be GC'd or not. What I care about is whether it can be GC'd.

Thank you for taking out your time to help me.

EDIT: To make the context clearer, here's the basic idea of the concerned code as I use it in my app.

Repository.kt:

interface Repository {

    //Other code.

    fun getUserPrefs(): Flowable<UserPreference>
}

MyViewModel.kt:

class MyViewModel(private val repository: Repository): ViewModel() {

    init {
        repository.getUserPrefs()
            .subscribe { //Code with UI state side effects }
    }
}

In my app, Repository's implementation will be a singleton.For those not familiar with Android, just know that ViewModel's can last for pretty long time. It's work is basically to be responsible for managing UI state.

AnEnigmaticBug
  • 939
  • 9
  • 17
  • 2
    I don't know the specific implementation details, but in order for the `Observable` to receive emitted items, the emitter needs to keep a reference to it, so as long as the emitter is not garbage collected, the `Observable` won't be garbage collected as well. – user2340612 Jun 26 '18 at 12:48
  • @user2340612 Thank you. It makes sense now. I'll wait for more answers just to be sure. But thank you very much. BTW I have mostly used C++ till 6-8 months ago. I'm a bit experienced with Java and Kotlin. I am productive in them but once in a while, I find myself stumped about these things. I don't have a solid knowledge about GC. Can you recommend any sources to help me give more clarity in this matter? – AnEnigmaticBug Jun 26 '18 at 12:54
  • 1
    I read [this blog post](https://www.dynatrace.com/resources/ebooks/javabook/how-garbage-collection-works/) that was really interesting for me – user2340612 Jun 26 '18 at 12:57
  • 1
    Yet another “will the garbage collector break this program” question… **No** the garbage collector is there, so the programmer can stop worrying about memory, not to have new worries about the garbage collector. There wouldn’t be the slightest sense in adding a garbage collector that breaks programs by collecting objects which are still in use. Unless the documentation of `subscribe` says explicitly to use some kind of *weak* references to allow the object to get collected (which wouldn’t make much sense either, but there are APIs doing such nonsensical things). – Holger Jun 26 '18 at 14:49
  • @Holger I had this doubt because as I mentioned, I'm relatively new to garbage collected languages. I understand that an ideal GC shouldn't get in the way of a programmer but I didn't know that in real life also, such issues don't happen. I was just trying to look out for cases in which issues might occur. Just to be safe. Your comment made me see the point though. Thanks for your help. – AnEnigmaticBug Jun 26 '18 at 15:19
  • @user2340612 A big thanks for the blog post! Now, things are clearer for me :) – AnEnigmaticBug Jun 26 '18 at 15:21
  • @NightMare well, all garbage collectors are conservative in that, if in doubt, they will keep an object if they can’t prove whether it is unused. Even simple or naive gc algorithms like reference counting fulfill this property. In fact, even JVMs without a garbage collector fulfill this requirement. A garbage collector which reclaims an object that is still in use must be considered broken, as preventing precisely such scenarios is the very purpose of garbage collectors. In that regard it’s funny that almost every day, a new “will gc break the following code” question arrives at Stackoverflow… – Holger Jun 27 '18 at 07:13

1 Answers1

3

So after the sleep main exits and the emitting stops. If you try it with Thread.sleep(1000) you'll see that it only outputs

0
1

The reason for this is that your program terminates.

What you want here might be blockingSubscribe:

getObservable().blockingSubscribe { println(it) }

which will only return once the Observable is finished.

Note that you can subscribe on 3 types of events: onNext, onError and onComplete:

getObservable().blockingSubscribe({
    println(it)
}, {
    throw it
}, {
    println("finished")
})

Subscribing to all 3 will not change the fact that the subscriber runs out of scope so you'll still need to use blockingSubscribe. If you want to offload work between threads you can use subscribeOn and observeOn:

getObservable()
        .subscribeOn(Schedulers.computation())
        .observeOn(Schedulers.single())
        .blockingSubscribe {
            println(it)
        }

You can read more about these in this question.

About garbage collection:

The Java garbage collector is intelligent enough to reclaim resources which have references to each other but are not referenced by the so called "root reference":

 (Root reference)

 (obj0) --> (obj1)
  \          /
   \        /
    \      /
    (obj2)

^^^--- obj0, 1 and 2 are eligible for garbage collection

So why does your Observable keep running despite it being detached from other objects? The answer is that there are multiple types of "root" references in Java:

  • Local variables
  • Active Java threads
  • Static variables
  • JNI References

In your case when you call subscribe on your Observable it offloads work to RxJava-s threads which are "root" references in themselves so even if you don't have a reference of any of those objects they will still keep running ad infinitum or until the Threads terminate.

Adam Arold
  • 29,285
  • 22
  • 112
  • 207
  • Thanks for your reply. The way I see it is that calling `subscribe()` doesn't wait for the thread used by the `Observable` to finish while calling `blockingSubscribe()` waits for it. In my situation, the `Observable` will last for a significant chunk of time of my application. The issue is not whether the `Observable` will get to finish. It is whether it will be garbage collected before my application finishes with the application still depending on it. So, for the purposes of this question assume that the program will run for a long time(such that GC may run). – AnEnigmaticBug Jun 26 '18 at 14:27
  • How do they depend on your `Observable`? Can you show us some more code? – Adam Arold Jun 26 '18 at 14:32
  • I edited the question to add the details. If they're insufficient, please tell me. – AnEnigmaticBug Jun 26 '18 at 14:38
  • 1
    Cool, now I understand your problem. I fixed the answer. – Adam Arold Jun 26 '18 at 15:22
  • 1
    Thank you! This explanation is simply brilliant!! This makes it all crystal clear. I really hope you've a nice day ahead. Cheers :) – AnEnigmaticBug Jun 26 '18 at 15:36
  • 3
    The sentence "The Java garbage collector is intelligent enough to reclaim resources which have references to each other but not to the so called "root reference":" is wrong. It does not matter what the to be reclaimed resource refers *to*; what matter is what they're referred *from*. Kept are all objects transitively referred from a root reference (= reachable from root). – maaartinus Jun 26 '18 at 20:44