Java 会话对象是否占用我的应用程序中的资源?韩元';垃圾收集器不能移除它们吗?

Java 会话对象是否占用我的应用程序中的资源?韩元';垃圾收集器不能移除它们吗?,java,session,servlets,memory,cookies,Java,Session,Servlets,Memory,Cookies,我在HeadFirstJSP和Servlets页面:241中遇到了一部分,其中说我们必须摆脱会话,如图所示: 随后,他们提出了方法invalidate()和setMaxInactiveInterval(),用于减少服务器中的过时会话数量。读完那篇文章后,我有点困惑 首先,我使用httpsessions=request.getSession()获取Servlet代码中的会话对象,然后执行一些操作。知道一个请求将为该Servlet生成一个线程,这意味着变量s将只对该给定线程有作用域。一旦线程完成,

我在HeadFirstJSP和Servlets页面:241中遇到了一部分,其中说我们必须摆脱会话,如图所示:

随后,他们提出了方法
invalidate()
setMaxInactiveInterval()
,用于减少服务器中的过时会话数量。读完那篇文章后,我有点困惑

首先,我使用
httpsessions=request.getSession()
获取Servlet代码中的会话对象,然后执行一些操作。知道一个请求将为该Servlet生成一个线程,这意味着变量
s
将只对该给定线程有作用域。一旦线程完成,变量
s
将不存在。这进一步意味着堆中的会话对象将不会有来自
s
=垃圾收集的活动引用

所以,如果没有新的请求,就不应该有任何会话对象占用我的资源,对吗?那为什么这本书告诉我必须摆脱它们呢?垃圾收集器不应该单独完成它的工作吗

有人能纠正我的错误吗?会话对象真的存储在堆中吗?因为我想不出它们可能在哪里。

这一点及其公认的答案很好地说明了HTTP会话机制的目的

如果您想在请求之间保持状态,那么该状态需要存储在某个地方。我相信大多数应用服务器在默认情况下都会使用堆。您可以将其视为以用户会话id为键的映射,以及包含存储数据的对象作为其值

除非您采取措施从地图中删除对象,否则此地图将永远增长,通过在用户注销时使会话对象无效,或设置某种不活动限制,使应用程序服务器在设置的时间段后自行清理旧条目。

这及其接受的答案很好地说明了HTTP会话机制的目的

如果您想在请求之间保持状态,那么该状态需要存储在某个地方。我相信大多数应用服务器在默认情况下都会使用堆。您可以将其视为以用户会话id为键的映射,以及包含存储数据的对象作为其值


除非您采取措施删除其中的对象,否则此映射将永远增长,方法是在用户注销时使会话对象无效,或者设置某种不活动限制,使应用程序服务器在一段时间后自行清理旧条目。

这里有很多东西要打开,让我们一个接一个地看

会话和cookies HTTP是一种无状态协议。这意味着,对于服务器,每个HTTP请求都被视为独立于其他HTTP请求。因此,如果您向同一个服务器发出多个请求,服务器实际上并不关心它们是否来自同一个客户端:接收请求并生成响应,接收另一个请求并生成另一个响应,依此类推

但是,在某些情况下,您需要将来自同一用户的一组请求标识为与服务器进行较长时间的交互,而不仅仅是孤立的请求。这里是会话和cookies的用武之地

会话标识同一用户与服务器的多个交互,并允许您维护用户标识和一些有用的数据,这些数据的生命周期可以跨越所有请求。这意味着一个会话是无效的

会话基本上是服务器保存在内存中的对象,它充当在请求之间要保存的任何数据的容器。这个对象也可以在磁盘上或数据库内保存(例如,当您重新启动服务器并且不想失去活动会话)时,但为了简单起见,只需将其视为内存中的对象。是的,它存储在堆中

因此,如果应用程序需要在请求之间存储状态,则可以在服务器上创建会话对象。但是,如何将属于某个会话的请求与不属于该会话的其他请求区分开来呢?答案是饼干

当用户发出第一个请求时,服务器可以创建一个会话,并返回一个添加到响应中的会话ID。当用户发出另一个请求时,会话ID被发送回服务器,现在该请求被标识为更大交互的一部分,会话的一部分。哪节课?因此,会话是存储在服务器上的对象,任何作为会话交互一部分的请求都需要用会话ID标识

垃圾收集会话 由于会话对象是位于堆上的Java对象,因此可以对其进行垃圾收集。然而,事情并不是那么简单

例如,比较以下几段代码。这:

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    // ...
    Object s = new Object();
    // ...
}
为此:

protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    // ...
    HttpSession s = request.getSession();
    // ...
}
在第一个示例中,您创建了一个存储在堆上的对象。一旦
doGet
方法结束,这个对象就有资格进行垃圾收集,因为除了
s
之外,没有其他对该对象的引用,该方法返回时超出了范围

这里的关键部分是“不再引用”。当无法再从JVM中存在的任何活动引用访问对象时,对象符合垃圾收集的条件。当
doGet
方法结束时,
s
消失,因此没有任何东西指向您创建的对象。使用
HttpSession
情况就不同了

在第二段代码中,您没有创建会话对象,而是要求服务器“给您”一个会话对象。假设服务器保留了一个映射,其中包含会话对象作为值