【问题标题】:Will the Observable stop emitting midway in this scenario due to being garbage collected?在这种情况下,Observable 会因为被垃圾收集而停止发射吗?
【发布时间】:2018-06-26 12:42:38
【问题描述】:

我想知道在这种情况下 observable 是否有资格被垃圾收集:

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)
}

它不会停止发射。但我不能用它来确定它不会在一段时间后被 GC,因为它可能只是在这么短的时间内没有触发 GC。

我的猜测是它应该是 GC'd。我们没有对从getObservable() 函数返回的Observable 的引用,因为我们不能再访问它了。再次调用该函数将给出不同的新Observable。由于我们无法访问Observable 本身,因此其余对象也无法访问。所以,我认为所有这些都可以在任何随机时间被垃圾收集。

我在 Android 应用中的一些代码使用了一些类似的代码。这是一个Observable,我希望它和Application一样长。因为,GC 会收集任何垃圾,我不希望我的Observable 在我的应用程序中间被 GC。所以,请记住,我不是在寻找告诉我它是否会被 GC 的答案。我关心的是能不能被GC。

感谢您抽出时间来帮助我。

编辑:为了使上下文更清晰,这是我在应用程序中使用相关代码的基本思想。

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 }
    }
}

在我的应用程序中,Repository 的实现将是一个单例。对于那些不熟悉 Android 的人,只知道 ViewModel 可以持续很长时间。它的工作基本上是负责管理UI状态。

【问题讨论】:

  • 我不知道具体的实现细节,但是为了让Observable接收发射的项目,发射器需要保持对它的引用,所以只要发射器不是垃圾收集,Observable 也不会被垃圾收集。
  • @user2340612 谢谢。现在说得通了。我会等待更多的答案来确定。但是非常感谢。顺便说一句,直到 6-8 个月前,我大部分时间都在使用 C++。我对 Java 和 Kotlin 有点经验。我在他们身上很有效率,但有时,我发现自己被这些事情难住了。我对GC没有扎实的知识。你能推荐任何来源来帮助我更清楚地说明这个问题吗?
  • 我读到了this blog post,这对我来说真的很有趣
  • 又一个“垃圾收集器会破坏这个程序”的问题...... 没有垃圾收集器在那里,所以程序员可以不用担心内存,不用再担心垃圾收集器。添加一个通过收集仍在使用的对象来破坏程序的垃圾收集器没有任何意义。除非subscribe 的文档明确说明要使用某种 weak 引用来允许收集对象(这也没有多大意义,但是有些 API 会做这些无意义的事情)。
  • @Holger 我有这个疑问,因为正如我所提到的,我对垃圾收集语言还比较陌生。我知道理想的 GC 不应该妨碍程序员,但我不知道在现实生活中也不会发生此类问题。我只是想找出可能出现问题的情况。只是为了安全。你的评论让我明白了这一点。感谢您的帮助。

标签: java kotlin garbage-collection rx-java2


【解决方案1】:

所以在sleep main 退出并且发射停止之后。如果你用Thread.sleep(1000) 试试,你会发现它只输出

0
1

原因是你的程序终止了。

你想要的可能是blockingSubscribe:

getObservable().blockingSubscribe { println(it) }

只有在 Observable 完成后才会返回。

请注意,您可以订阅 3 种类型的事件:onNextonErroronComplete

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

订阅所有 3 项不会改变订阅者超出范围的事实,因此您仍需要使用 blockingSubscribe。如果你想卸载线程之间的工作,你可以使用subscribeOnobserveOn

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

您可以阅读有关这些in this question 的更多信息。

关于垃圾回收

Java 垃圾收集器足够智能,可以回收相互引用但未被所谓的“根引用”引用的资源:

 (Root reference)

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

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

那么为什么你的Observable 会在与其他对象分离的情况下继续运行?答案是 Java 中有多种类型的“根”引用:

  • 局部变量
  • 活动 Java 线程
  • 静态变量
  • JNI 参考资料

在您的情况下,当您在 Observable 上调用 subscribe 时,它会将工作卸载到 RxJava-s 线程,这些线程本身就是“根”引用,因此即使您没有任何这些对象的引用,它们也会仍然无限期地运行广告或直到Threads 终止。

【讨论】:

  • 感谢您的回复。我看到它的方式是调用subscribe() 不会等待Observable 使用的线程完成,而调用blockingSubscribe() 会等待它。在我的情况下,Observable 将在我的申请中持续很长时间。问题不在于Observable 是否会完成。它是否会在我的应用程序完成之前被垃圾收集,而应用程序仍然依赖于它。所以,为了这个问题的目的,假设程序会运行很长时间(这样 GC 可能会运行)。
  • 他们如何依赖你的Observable?你能再给我们看一些代码吗?
  • 酷,现在我明白你的问题了。我确定了答案。
  • 谢谢!这个解释简直太棒了!!这让一切都一清二楚。我真的希望你有一个美好的一天。干杯:)
  • “Java 垃圾收集器足够智能,可以回收相互引用但不引用所谓的“根引用”的资源:”这句话是错误的。要回收的资源 指向 的对象并不重要;重要的是他们从 被推荐。保留是从根引用传递引用的所有对象(= 可从根访问)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
  • 2015-10-08
  • 1970-01-01
  • 2015-05-04
相关资源
最近更新 更多