4

假设我有一个名为的托管 bean假设A有对另一个托管 bean 的引用并声明为. 引用另一个具有更长范围的 bean的事实是否会阻止在结束时收集垃圾?@RequestScopedABB@SessionScopedAAHttpRequest

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

4

4 回答 4

6

A引用另一个具有更长范围的 bean的事实是否会阻止A在结束时收集垃圾HttpRequest

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

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


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

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

总而言之,托管 bean 范围不应该根据 GC 行为来选择,而是根据它所拥有的数据来选择。另请参阅如何选择正确的 bean 范围?

于 2013-01-14T15:42:45.300 回答
1

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

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

于 2013-01-14T15:17:41.697 回答
0

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

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

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

于 2013-01-14T15:30:14.540 回答
0

在任何情况下,如果从根对象之一引用您的对象(只要有一种方法可以从 Main() 或任何其他静态/单例/bean 中获取它,不管它有多深) ) 它不会被 GC 收集

于 2013-01-14T15:30:18.127 回答