【问题标题】:Understanding garbage collection in Java for objects managed by container了解 Java 中由容器管理的对象的垃圾收集
【发布时间】:2013-01-14 15:14:49
【问题描述】:

假设我有一个名为A 的托管bean,即@RequestScoped 假设A 引用了另一个托管bean B,并且B 被声明为@SessionScopedA 引用另一个具有更长范围的 bean 的事实是否会阻止 AHttpRequest 的末尾收集垃圾?

如果B 包含对A 的引用,情况是否会反过来改变?如果是,那为什么?

【问题讨论】:

  • 不...但是如果更长范围的 bean B 有对 A 的引用,那么在收集 B 之前不能对 A 进行垃圾收集。
  • @Charlie 你能解释一下为什么第一个问题的答案是“否”,第二个问题是“是”。
  • 当一个对象无法访问时,它可以被垃圾回收。即当没有对象在任何线程上执行时,或者任何静态引用都持有该对象的强引用。考虑进行垃圾回收的对象持有对其他对象的引用这一事实无关紧要。

标签: java jsf garbage-collection


【解决方案1】:

A 引用另一个具有更长范围的 bean 的事实是否会阻止 AHttpRequest 末尾收集垃圾?

不,对象实例只有在不再引用它时才有资格进行 GC。

默认情况下,请求范围的 bean 仅在当前 HTTP 请求中引用(作为 request attribute)。因此,如果 HTTP 请求完成并被销毁,则请求范围的 bean 将完全取消引用,因此有资格进行 GC。请求范围 bean 又包含对会话范围 bean 的引用,这与 GC 完全无关。只有当会话范围的 bean 没有在任何地方被引用时(例如,当会话过期时),会话范围的 bean 才会反过来也符合 GC 的条件。


如果 B 包含对 A 的引用,情况是否会反过来改变?如果是,那为什么?

是的,它会改变。默认情况下,会话范围的 bean 仅在 HTTP 会话中引用(作为 session attribute),它的寿命比 HTTP 请求长。因此,请求范围的 bean 将与已建立的 HTTP 会话一样长。这将导致潜在的数据完整性问题,因为您引用的东西本应不应该存在那么久。这就是为什么 JSF 不允许您通过 @ManagedProperty 在更宽范围的 bean 中注入更窄范围的 bean 的原因之一。

总而言之,托管 bean 范围的选择不应基于 GC 行为,而应基于其持有的数据。另见How to choose the right bean scope?

【讨论】:

    【解决方案2】:

    No.GC 仅取决于指向对象的活动引用的数量,而不是其他方式。 JVM 总是维护一组活跃的引用。任何从这个根引用集中无法访问的东西都有资格进行垃圾回收。所以即使一个对象是 A 指向另一个活动的对象 B,如果内存中没有其他对象引用 A,那么 A 是可用的用于 GC。

    在您的情况下,A 的范围仅限于单个请求。因此,当服务器完成该请求处理时,如果没有内存泄漏,A 将可用于 gc。B 将保留在内存中,因为它具有会话范围。

    【讨论】:

    【解决方案3】:

    在您的示例中,您有这种情况:请求范围引用对象 A、A 和会话范围引用对象 B。当请求结束时,它被删除,因此没有任何引用对象 A。它可以被垃圾收集。之后 Session 仍然引用对象 B 并且无法收集。根据Java规范:

    当任何代码无法访问某个对象时,它就有资格进行垃圾回收。

    这意味着当对象不可访问时很简单。在这种情况下,A 将无法访问,但 B 会。

    【讨论】:

      【解决方案4】:

      在任何情况下,如果从根对象之一引用您的对象(只要有办法从 Main() 或任何其他静态/单例/ bean 什么)它不会被 GC 收集

      【讨论】:

        猜你喜欢
        • 2015-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-09
        • 1970-01-01
        • 2012-08-12
        相关资源
        最近更新 更多