假设我有一个名为A
的托管bean,@RequestScoped
假设A
引用另一个托管bean B
并声明B
是@SessionScoped
。 A
是否具有对具有更长范围的另一个bean的引用这一事实是否会阻止A
在HttpRequest
结束时收集垃圾?
如果B
包含对A
的引用,那么情况会发生相反的变化吗?如果是,那么为什么?
答案 0 :(得分:6)
A
是否具有对具有更长范围的另一个bean的引用这一事实是否会阻止A
在HttpRequest
结束时收集垃圾? < / p>
不,如果没有对它的引用,则对象实例仅适用于GC。
默认情况下,请求范围bean仅在当前HTTP请求中引用(作为request attribute)。因此,如果HTTP请求完成并被销毁,那么请求范围的bean将被完全取消引用,因此符合GC的条件。请求范围bean依次包含对会话范围bean的引用,这与GC完全无关。只有当会话范围bean没有被引用到任何地方时(例如,当会话已经过期时),那么会话范围的bean反过来也可以用于GC。
如果B包含对A的引用,那么情况会改变吗?如果是,那么为什么?
是的,它会改变。默认情况下,会话范围bean仅在HTTP会话中引用(作为session attribute),其寿命比HTTP请求长。因此,只要建立了HTTP会话,请求范围的bean就会存在。这将导致潜在的数据完整性问题,因为您引用的东西应该不应该存在那么久。这就是为什么JSF不允许您通过@ManagedProperty
在更广泛的范围内的bean中注入更窄的范围bean的原因之一。
总而言之,不应该根据GC行为选择托管bean作用域,而应该基于它保存的数据。另请参阅How to choose the right bean scope?
答案 1 :(得分:1)
No.GC仅取决于有多少实时引用指向对象,而不是另一种方式。 JVM始终维护一组活动的引用。从这个根引用集无法访问的任何东西都有资格进行垃圾收集。即使一个对象是A指向另一个正在运行的对象B,如果内存中没有其他对象引用了A,那么A是可用的对于GC。
在您的情况下,A的范围仅限于单个请求。因此,当服务器完成该请求处理时,如果没有内存泄漏,则A将可用于gc.B将保留在内存中,因为它具有会话范围。< / p>
答案 2 :(得分:0)
在您的示例中,您遇到以下情况:请求范围引用对象A,A和会话范围引用对象B.当请求结束时,它将被删除,因此不会引用对象A.它可以被垃圾回收。在该会话之后仍然引用对象B并且它无法收集。根据Java规范:
当任何代码无法访问对象时,该对象就有资格进行垃圾回收。
这意味着当对象无法访问时很简单。在这种情况下,A将无法访问,但B将是。
答案 3 :(得分:0)
在任何情况下,如果从一个根对象中引用了你的对象(只要有从Main()或任何其他静态/单例/到达它的方式,它无论多深。 bean什么都没有)它不会被GC收集