了解Java中容器管理的对象的垃圾收集

了解Java中容器管理的对象的垃圾收集,java,jsf,garbage-collection,Java,Jsf,Garbage Collection,假设我有一个名为a的托管bean,它是@RequestScoped让我们假设a引用了另一个托管beanB,并且B被声明为@SessionScoped。A引用了另一个作用域较长的bean这一事实是否会阻止A在HttpRequest结束时收集垃圾 如果B包含对a的引用,情况是否会改变?如果是,为什么?否。GC只取决于指向对象的活动引用的数量,而不是相反。 JVM总是维护一组活动的引用。任何无法从此引用根集访问的对象都有资格进行垃圾收集。因此,即使对象A指向另一个活动的对象B,如果内存中没有其他对象引

假设我有一个名为
a
的托管bean,它是
@RequestScoped
让我们假设
a
引用了另一个托管bean
B
,并且
B
被声明为
@SessionScoped
A
引用了另一个作用域较长的bean这一事实是否会阻止
A
HttpRequest
结束时收集垃圾


如果
B
包含对
a
的引用,情况是否会改变?如果是,为什么?

否。GC只取决于指向对象的活动引用的数量,而不是相反。 JVM总是维护一组活动的引用。任何无法从此引用根集访问的对象都有资格进行垃圾收集。因此,即使对象A指向另一个活动的对象B,如果内存中没有其他对象引用A,则A也可用于GC


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

在您的示例中,您遇到了以下情况:请求作用域引用对象A,A和会话作用域引用对象B。当请求结束时,它将被删除,因此不会引用对象A。它可以被垃圾收集。在该会话之后,仍然引用对象B,因此无法收集该对象。根据Java规范:

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


这意味着当对象不可访问时简单。在这种情况下,A是不可访问的,但B是可访问的。

在任何情况下,如果有一个根对象对您的对象的引用(不管它有多深,只要有办法从Main()或任何其他静态/单例/bean访问它),GC都不会收集它

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中注入范围更窄的bean的原因之一


总之,托管bean范围不应该基于GC行为而选择,而是基于它所持有的数据。另请参见

否。。。但是,如果作用域较长的bean B引用了a,则在B被收集之前,a无法被垃圾收集。@Charlie,请解释为什么第一个问题的答案是“否”,第二个问题的答案是“是”。当无法访问对象时,对象可以被垃圾收集。i、 当没有对象在任何线程上执行时,或者任何静态引用都持有对该对象的强引用。考虑进行垃圾收集的对象包含对其他对象的引用这一事实无关紧要。请您详细说明一下您的答案。