Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Tomcat: утечка памяти в Heap Space, как отловить гада? 
V
    Опции темы
COVD
Дата 19.12.2008, 06:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 4
Всего: 43



Цитата

А если язвительное...


 smile я неловко выразился. Уточнял, баг это или фича, что "треды ... не отпускают..". Но, наверное, диагноз не очевиден. 
PM MAIL   Вверх
Stampede
Дата 19.12.2008, 08:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 66
Всего: 144



Цитата(COVD @  18.12.2008,  21:46 Найти цитируемый пост)
Уточнял, баг это или фича, что "треды ... не отпускают.."


Ах, вот оно как оказывается smile

Знаешь, COVD, этот случай подтвердил мою давнишнюю теорию, что большинство конфликтов порождаются элементарным недопониманием, кто чего имел в виду. Ну хорошо, я рад, что все разрешилось без мордобития и эскалации напряженности. Каковой факт я отчасти ставлю в заслугу самому себе: много слов крутилось у меня на языке, но я выбрал самые нейтральные smile

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

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

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



--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
ivg
Дата 19.12.2008, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 32
Всего: 81



Позволю себе сделать небольшое дополнение по теме. По моему скромному разумению лучше делать так:
Код

    public class BreezeController implements Controller {
        ...
        public void service(HttpServletRequest req, HttpServletResponse resp, ServletContext sctx) {
            ...
            ThreadContext tc = Application.getThreadContext();
            RequestContext oldContext = tc.get(RequestContext.DEFAULT_NAME);
            tc.put(RequestContext.DEFAULT_NAME, new RequestContext(sctx, req, resp));
            try {
                ...
            } finally {
                ...
                tc.put(RequestContext.DEFAULT_NAME, oldContext);
            }
        }
    }

Ну то есть идея понятна - не обнулять/удалять контекст из ThreadLocal, а возвращать старое значение перед возвратом управления контейнеру.
Это нужно во избежании потери нашего контекста, например при использовании RequestDispatcher.
PM MAIL   Вверх
Stampede
Дата 19.12.2008, 11:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 66
Всего: 144



Цитата(ivg @  19.12.2008,  02:11 Найти цитируемый пост)
Это нужно во избежании потери нашего контекста, например при использовании RequestDispatcher.


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

А вообще в архитектуре Бриза контроллер - это фактически точка входа во фреймворк (как он видится со стороны запроса), и RequestDispatcher отрабатывает уже внутри него, так что до сих пор проблем с потерей контекста не возникало.


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
necromancer
Дата 19.12.2008, 15:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 317
Регистрация: 26.7.2006
Где: Москва

Репутация: 6
Всего: 7



to Stampede: а вы не хотели бы выложить исходники велкикого и ужастного breeze?


--------------------
С уважением, 
                 Виталий Смык
----------------------------------------------------------------------------------------------
SCJP, SCWCD, OCA
http://dev.maryno.net/video/
PM MAIL WWW ICQ Skype   Вверх
ivg
Дата 19.12.2008, 20:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 32
Всего: 81



Цитата(Stampede @  19.12.2008,  14:55 Найти цитируемый пост)
контроллер - это фактически точка входа во фреймворк (как он видится со стороны запроса), и RequestDispatcher отрабатывает уже внутри него

На всякий случай запощу пример потери контекста, о которой я говорил:
Код

package test;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestServlet extends HttpServlet {

    private static final String REQUEST_DEEP_NAME = "REQUEST_DEEP";
    private static final ThreadLocal<String> CONTEXT = new ThreadLocal<String>();
    
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        
        CONTEXT.set("Data");
        try {
            this.doService(req, resp);
        } finally {
            CONTEXT.remove();
        }
    }
    
    private void doService(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        
        Integer deep = (Integer)req.getAttribute(REQUEST_DEEP_NAME);
        Writer w = resp.getWriter();
        if (deep == null) {
            req.setAttribute(REQUEST_DEEP_NAME, Integer.valueOf(1));
            resp.setContentType("text/plain");
            w.write("-- begin " + CONTEXT.get() + " --\n");
            req.getRequestDispatcher("/").include(req, resp);
            w.write("-- end " + CONTEXT.get() + " --\n");
        } else {
            w.write("< body >\n");
        }
    }
}


web.xml:
Код

<web-app ...>
    ...
    <servlet>
        <display-name>TestServlet</display-name>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>test.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>


Это сообщение отредактировал(а) ivg - 19.12.2008, 21:15
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0558 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.