Используют ли объекты сеанса ресурсы в моем приложении? Разве сборщик мусора не удалит их?

Я наткнулся на часть на странице Head First JSP и Servlets: 241, где говорится, что мы должны избавиться от сеансов, как показано на этом рисунке:

Позже они представляют методы invalidate() и setMaxInactiveInterval(), которые используются для уменьшения количества устаревших сессий на нашем сервере. Прочитав это, я немного запутался.

Для начала я получаю объект сеанса внутри кода сервлета, используя HttpSession s = request.getSession(), а затем выполняю некоторые операции. Знание того, что один запрос создаст один поток для этого сервлета, означает, что переменная s будет иметь область действия только для этого данного потока. После завершения потока переменная s перестанет существовать. Что также означает, что объект сеанса в куче не будет иметь активной ссылки из s = сбор мусора.

Так что, если новых запросов нет, не должно быть никаких объектов сеанса, использующих мои ресурсы, верно? Так почему же книга говорит мне, что я должен избавиться от них? Разве сборщик мусора не должен делать свою работу в одиночку?

Может ли кто-нибудь поправить меня, сказав, что я написал неправильно? И действительно ли объекты сеанса хранятся внутри кучи? Поскольку я не могу придумать никакого другого места, где они могли бы быть.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
466
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Этот вопрос и принятый на него ответ дают хорошее представление о том, для чего предназначен механизм сеанса HTTP.

Если вы хотите сохранять состояние между запросами, то это состояние нужно где-то хранить. Я считаю, что большинство серверов приложений по умолчанию будут использовать для этого кучу. Вы можете представить себе, что это карта с идентификатором сеанса пользователя в качестве ключа и объектом, содержащим сохраненные данные в качестве его значения.

Эта карта будет расти вечно, если вы не предпримете никаких действий по удалению из нее объектов, либо аннулировав объект сеанса, когда пользователь выйдет из системы, либо установив какое-то ограничение бездействия, которое позволяет самому серверу приложений очищать старые записи через заданный период времени. .

Могу ли я тогда сказать, что сеанс хранится на стороне сервера, а также в куки-файлах пользователя? Поскольку определение того, что он находится на сервере, сбивает с толку ... серверу необходимо проверить идентификатор и сравнить его с тем, что «у него есть». Я близок к этому?

Stefan 19.12.2020 11:44

Данные сеанса хранятся на сервере. Файл cookie пользователя содержит только ключевое значение, позволяющее серверу искать значения, которые были сохранены в сеансе. Когда вы создаете сеанс на сервере, сервер передает идентификатор сеанса обратно клиенту в файле cookie. Клиент передает этот файл cookie обратно при всех последующих запросах, позволяя серверу получить идентификатор, а затем найти все данные, связанные с сеансом.

DaveH 19.12.2020 13:17

Спасибо! Срок действия куки-файлов по умолчанию равен времени, пока открыт браузер. Я знаю, что могу увеличить срок жизни файла cookie, но могу ли я продлить срок службы файла cookie, содержащего идентификатор сеанса? Я знаю, что это может нарушить правила (поскольку сессия существует, пока открыт браузер), но могу ли я сделать это теоретически?

Stefan 19.12.2020 13:48

Я не думаю, что есть что-то особенное в файле cookie, который содержит идентификатор сеанса, поэтому вы, вероятно, могли бы расширить его, если хотите.

DaveH 19.12.2020 18:25
Ответ принят как подходящий

Здесь довольно много вещей, которые нужно развернуть, так что давайте рассмотрим их одну за другой.

Сессии и файлы cookie

HTTP — это протокол без сохранения состояния. Это означает, что для сервера каждый HTTP-запрос рассматривается как независимый от других HTTP-запросов. Таким образом, если вы делаете несколько запросов к одному и тому же серверу, серверу все равно, исходят ли они от одного и того же клиента или нет: получен запрос и сгенерирован ответ, получен другой запрос и сгенерирован еще один ответ, и так далее. на.

Но бывают ситуации, когда вам нужно идентифицировать кучу запросов как исходящих от одного и того же пользователя, как более длительное взаимодействие с сервером, а не только отдельные запросы. И вот здесь на помощь приходят сеансы и файлы cookie.

Сеанс идентифицирует несколько взаимодействий одного и того же пользователя с сервером и позволяет вам поддерживать личность пользователя и некоторые полезные данные, время жизни которых может охватывать все запросы. Это означает, что сеанс с состоянием, а не без состояния.

Сеанс — это, по сути, объект, который сервер хранит в памяти, который действует как контейнер для любых данных, которые вы хотите сохранить между запросами. Этот объект также может быть сохранен на диске или внутри базы данных (например, когда вы перезапускаете сервер и не хотите терять активные сеансы), но для простоты просто считайте его объектом в памяти. И да, он хранится внутри HEAP.

Таким образом, на сервере вы можете создать объект сеанса, если вашему приложению необходимо сохранять состояние между запросами. Но как отличить запросы, принадлежащие одному сеансу, от других запросов, не принадлежащих этому сеансу? Ответ - печенье.

Когда пользователь делает свой первый запрос, сервер может создать сеанс и вернуть вам SESSION_ID, который будет добавлен к ответу. Когда пользователь затем делает другой запрос, SESSION_ID отправляется обратно на сервер, и теперь этот запрос идентифицируется как часть более крупного взаимодействия, часть сеанса. Какой сеанс? Это идентифицируется с SESSION_ID. Таким образом, сеанс — это объект, хранящийся на сервере, и любые запросы, которые являются частью этого взаимодействия сеанса, должны быть идентифицированы с помощью SESSION_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 все иначе.

Во втором фрагменте кода вы не создаете объект сеанса, вы просите сервер «дать вам» объект сеанса. Представьте себе карту, сохраненную сервером, которая содержит объекты сеанса в качестве значений, а идентификаторы SESSION_ID являются ключами для доступа к ним. Когда вы просите сервер предоставить вам сеанс с HttpSession s = request.getSession(), он просматривает файл cookie SESSION_ID из запроса, чтобы найти сеанс, связанный с этим запросом, и дает вам ссылку на объект сеанса. Теперь у вас есть две ссылки на объект сеанса, один хранится на сервере в этой карте сеансов, а другой хранится в s. Когда метод doGet завершается, ссылка s исчезает, но сервер все еще хранит ссылку на объект сеанса (поскольку он нужен ему для дальнейших запросов, которые могут поступать как часть более крупного взаимодействия). В этом случае объект сеанса НЕ подходит для сборки мусора, потому что он доступен по активной ссылке в JVM, той, которая хранится на сервере.

Итак, если вы не избавитесь от сеансов, сервер не сможет узнать, полезен этот сеанс или бесполезен, потому что он не знает, будет ли позже сделан другой запрос, чтобы запросить его или нет. Таким образом, объекты сеанса остаются на сервере навсегда. Поскольку сервер может работать месяцами или годами без перезапуска или отключения, объекты сеанса могут накапливаться и потреблять всю память. Сборщик мусора не удалит их, потому что на них есть ссылки на сервере. В конечном итоге вы получите ошибку OutOfMemory, и ваш сервер выйдет из строя.

Время ожидания сеанса

Конечно, вы не хотите, чтобы ваш сервер рухнул. Поэтому вам нужно аннулировать сеансы и сказать серверу: «Эй, мне больше не нужен этот объект сеанса. Вы можете избавиться от него». В этом случае сервер удаляет его со своей карты, и теперь без каких-либо активных ссылок он может быть удален сборщиком мусора.

Но так как все это взаимодействие происходит по сети с HTTP, как упоминается в примере в книге, браузер может рухнуть, компьютер пользователя может рухнуть, пользователь может просто уйти. Таким образом, у вас может не быть возможности аннулировать сеанс и сказать серверу, что он может избавиться от него, поэтому он останется там навсегда.

И вот тут-то и появляются тайм-ауты сеанса. Когда вы создаете свое приложение, вы также настраиваете тайм-аут сеанса, чтобы сообщить серверу: «Эй, если в этом сеансе нет активности в течение X минут, вы можете избавиться от этого». Итак, теперь, если клиент просто уходит, не аннулируя сеанс, сервер может иметь отказоустойчивый механизм для избавления от просроченных сеансов, чтобы они не оставались навсегда в памяти.

Мужик, спасибо тебе большое, ты все рассказал! Короче говоря: ссылочная переменная s будет ссылаться на тот же объект, что и объект сеанса внутри памяти? Итак, две ссылки на один объект, верно? Поэтому, когда поток завершается, остается только одна ссылка (одна из карты). Я понял? :)

Stefan 20.12.2020 19:36

Да. Ваша ссылка s пропала, но с сервера осталась. Только когда сеанс станет недействительным или истечет время ожидания, сервер удалит свою ссылку, и тогда у вас будут нулевые ссылки, и объект сеанса может быть удален сборщиком мусора.

Bogdan 20.12.2020 19:47

Понял :) Этот ответ нуждается в большем количестве голосов, он превосходен. Даже в книге подробно это не описано. И еще один вопрос: могу ли я когда-нибудь увеличить срок жизни файла cookie, содержащего SESSION_ID? Я знаю, что это нарушит правила (файл cookie сеанса удаляется при закрытии браузера), но могу ли я это сделать? Я заметил, что они умно разработали его в сервлетах - метод getSession(), который технически возвращает сеанс, а не его файл cookie. Так что этот API фактически мешает мне это сделать. Верна ли моя догадка?

Stefan 20.12.2020 19:59

Если для файла cookie установлена ​​дата истечения срока действия, браузер должен хранить его до истечения срока действия, а не до тех пор, пока вы не закроете браузер. Найдите «Expires» в строке cookie в ответе HTTP или в консоли отладки браузера. Что касается установки возраста файла cookie, мне не совсем понятно, если это то, что вы ищете, но посмотрите на <cookie-config><max-age> в web.xml. См., например, этот пост: stackoverflow.com/questions/35105410/…

Bogdan 20.12.2020 20:45

Другие вопросы по теме