0

I'm having a really bad time trying to track down this OutOfMemoryError and I'd really appreciate some help. My application is split into the architecture part and a module which exposes some basic REST WS with database CRUD operations made by Hibernate. The main architecture has the only role of logging and managing properties and configurations (all of this is handled by Spring).

The application isn't doing anything so fancy but still after 2-3 hot redeploy with Tomcat 7 I'm getting an OutOfMemoryError. I've done an Heap dump and opened it with VisualVM and this is what I see:

enter image description here

As you can see, I'm having lots of Strings, char[] and byte[] around. The only class really manipulating this kind of data is the logger which is a servlet-filter only doing this:

@Override
public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        Map<String, String> requestMap = this
                .getTypesafeRequestMap(httpServletRequest);
        BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(
                httpServletRequest);
        BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper(
                httpServletResponse);

        final StringBuilder logMessage = new StringBuilder(
                "REST Request - ").append("[HTTP METHOD:")
                .append(httpServletRequest.getMethod())
                .append("] [PATH INFO:")
                .append(httpServletRequest.getRequestURI())
                .append("] [REQUEST PARAMETERS:").append(requestMap)
                .append("] [REQUEST BODY:")
                .append(bufferedRequest.getRequestBody())
                .append("] [REMOTE ADDRESS:")
                .append(httpServletRequest.getRemoteAddr()).append("]");
        long startTime = System.currentTimeMillis();
        chain.doFilter(bufferedRequest, bufferedResponse);
        long elapsed = System.currentTimeMillis() - startTime;
        logMessage.append(" [RESPONSE:")
                .append(bufferedResponse.getContent())
                .append("] [ELAPSED TIME:").append(elapsed).append("ms]");
        log.debug(logMessage.toString());
}

If the logger is not the cause of this, may it be due to some Spring/Hibernate/Tomcat/some library that I'm not aware of?

If you need anything else, like Spring configurations, feel free to ask.

Thank you!

Aurasphere
  • 3,841
  • 12
  • 44
  • 71
  • what are your tomcat memory settings (Xmx, PermSize)? – Alex Salauyou May 05 '16 at 16:19
  • Have you tried to allocate more memory for your web app when Tomcat, as application server, at startup ? Also try to figure out if "a dominator object" creates and holds many references (I encountered a case when Hibernate was the cause) – dumitru May 05 '16 at 16:20

2 Answers2

0

The problem is associated with the hot redeploy of JEE webapps. Not in Tomcat but on any JEE Servlet container.

There's a good explanation for it here:

What makes hot deployment a "hard problem"?

Community
  • 1
  • 1
Andres
  • 10,561
  • 4
  • 45
  • 63
  • 1
    Aside from being a link-only answer, that blog post appears quite outdated. Specifically, it asks to set a JVM parameter that no longer exists with Java 8, and Java 7 has been end of life for more than a year now ... – meriton May 05 '16 at 17:09
0

As you can see, I'm having lots of Strings, char[] and byte[] around. The only class really manipulating this kind of data is the logger which is a servlet-filter

That's really hard to believe. The hibernate entities do not contain a single string, HTTP requests are never stored in a char[], responses are never buffered, ...

Strings are such a ubiquitous datatype that nearly every library in your classpath will be using them extensively, the trick is finding which library is leaking them, and why.

To effectively analyze a heap dump, you should be using a tool that does not just list how many objects there are, but also analyzes the graph of object references to find out which objects are keeping those strings alive. Most commercial memory profiles do this very well. Barring that, the open source Eclipse Memory Analyzer is pretty good, too. It's been a while since I last used it, but for my last memory leak, MAT's standard leak suspect report correctly identified the object that caused the OutOfMemoryError.

meriton
  • 68,356
  • 14
  • 108
  • 175