Dan,

The only reason we are all looking for resource leaks (technically not memory leaks, but leaks nonetheless) is because it's the best explanation for why your connection pool seems to be running dry.

I don't think that switching to Tomcat (or TomEE) is going to make any difference.

-chris

On 8/15/25 12:33 PM, Daniel Schwartz wrote:


-----Original Message-----
From: Christopher Schultz <ch...@christopherschultz.net>
Sent: Friday, August 15, 2025 12:18 PM
To: users@tomcat.apache.org
Subject: Re: [EXTERNAL EMAIL] How to access a REST service

Daniel,

On 8/15/25 12:49 AM, Daniel Schwartz wrote:
Robert (and all),

I will work on answers your various questions.  However, I decided to first explore the 
comment (by someone) that a servlet can "swallow" an exception, which I take to 
mean that it can throw an exception without reporting the exception or terminating the 
program.

I have this system running on a PC identified as localhost. The test URL is:

https://urldefense.proofpoint.com/v2/url?u=http-3A__localhost-3A8080_H
olidaysRESTJSON-2D1.0-2DSNAPSHOT_webresources_holidaysandevents_countr
ies&d=DwICaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=AbCalLxzo
pgQUG9LLcXdB80OM-GtDfItX76RMxNYqz4&m=NKm1FUayvDzFHyhbqCI0JR32OpW1rfTed
HFkAoC_xT6Cjqt4-wsVFtYKPtR38vFY&s=4BYNb88ZN6WvyMyyZcR1FyT6Jg-qa4JSDa9P
xsSFgB4&e=

I ran two tests.  First, I wrote in code to throw an SQL exception, which did 
get caught in my catch clause, which printed out some messages and a stack 
trace.  The web browser showed the retrieved list of countries, but nothing 
else.

Second, I replaced the line that throws the SQL exception by one that tries to 
do a division by zero.  This of course was not caught, but it did print out a 
stack trace and reported a 505 error in the browser, and the program did 
terminate.

I take this to mean that exceptions are not being "swallowed" by my program.  
When/if an exception occurs, there is definitely some indication of this, either in the 
server.log or the browser.  Because I have never seen either of these actions, I'm fairly 
sure that my program is not throwing exceptions and all database connections are being 
closed immediately after they are used, i.e., no memory leaks in this respect.

The actual code fragments and outputs are copied below.

----------------------------------------------------------------
The code that throws the SQL exception
----------------------------------------------------------------
      @GET
      @Path("/countries")
      @Produces(MediaType.APPLICATION_JSON)
      public String getJsonCountries() {
          if (TempDataStorage.countryList == null) {
              Connection connection = null;
              try {
                  connection = dataSource.getConnection();
                  System.out.println("countries connection has been opened");
                  TempDataStorage.countryList = GetCountryList.doIt(connection);
                  throw new SQLException("testing sql exception");
//                connection.close();
//                System.out.println("countries connection has been closed");
              } catch (SQLException e) {
                  System.out.println(e);
                  System.out.println("catching sql exception");
                  if (connection != null) {
                      try {
                          connection.close();
                      } catch (SQLException ex) {
                          System.out.println(ex);
                      }
                  }
              }
          }

100% connection leak every time, guaranteed.

You are never closing the connection, because it's been commented out.
Perhaps this was just for testing, because I see you are throwing an exception.

DGS: When I put in the throw statement, I had to comment out those two lines 
because the Java compiler complains that they are unreachable.  This was just 
to test for what would happen if an SQL exception was thrown, in which case, 
yes, there will be a memory.  The point is that my program never throws SQL 
exceptions, because if it did, I would know about it.

The conn.close() *MUST* be in a finally {} block. Do not put it in the try 
block. Do not put it in the catch block. Always put it in the finally block.

DGS: Sounds like good advice.  I'll do this and see if it makes a difference.

------------------------------------------------------------------
The output in the server.log file
------------------------------------------------------------------
[2025-08-14T23:34:42.019-0400] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=40 
_ThreadName=Thread-8] [timeMillis: 1755228882019] [levelValue: 800] [[
    countries connection has been opened]]

[2025-08-14T23:34:42.022-0400] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=40 
_ThreadName=Thread-8] [timeMillis: 1755228882022] [levelValue: 800] [[
    java.sql.SQLException: testing sql exception
        at
com.worldholidaysandevents.restjsonwebservice.HolidaysRESTJSONResource
.getJsonCountries(HolidaysRESTJSONResource.java:54)

          ... stack trace ...

[2025-08-14T23:34:42.022-0400] [glassfish 4.1] [INFO] [] [] [tid: _ThreadID=40 
_ThreadName=Thread-8] [timeMillis: 1755228882022] [levelValue: 800] [[
    catching sql exception]]

... and the server does not crash. You can make any request without restarting 
Glassfish, right?

----------------------------------------------------------------
The code that divides by zero
----------------------------------------------------------------
      @GET
      @Path("/countries")
      @Produces(MediaType.APPLICATION_JSON)
      public String getJsonCountries() {
          if (TempDataStorage.countryList == null) {
              Connection connection = null;
              try {
                  connection = dataSource.getConnection();
                  System.out.println("countries connection has been opened");
                  TempDataStorage.countryList = GetCountryList.doIt(connection);
                  float something = 1/0;
                  connection.close();
                  System.out.println("countries connection has been closed");
              } catch (SQLException e) {
                  System.out.println(e);
                  System.out.println("catching sql exception");
                  if (connection != null) {
                      try {
                          connection.close();
                      } catch (SQLException ex) {
                          System.out.println(ex);
                      }
                  }
              }
          }


100% connection leak every time, guaranteed.

You are never closing the connection, because your code is throwing an uncaught 
exception (divide by zero) Perhaps this was just for testing, because I see you 
are intentionally dividing by zero.

DGS: Right.  This was to test for what would happen if a non-SQL exception were 
thrown, i.e., one that is not caught in the catch clause.   This created a 505 
error and the program quit running.  Here the point is that, if something like 
this were to happen, I would certainly know about it, and it has never 
happened, so no memory leak is being created in this way.

The conn.close() *MUST* be in a finally {} block. Do not put it in the try 
block. Do not put it in the catch block. Always put it in the finally block.

DGS: Thanks again.  I'll do this and see if it makes any difference in the 
connection pooling.

-chris


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to