Chris and all,

I think I found the answer.  

A few days ago, someone suggested that I try setting the Glassfish maximum pool 
size to 1 and see what happens.  I reported back that in Glassfish the minimum 
pool size is 8, to which someone responded that this seems strange.  I really 
didn't know.  But now I do.

Today I decided to run a test where I cleared out Glassfish so I could start 
from scratch.  I executed one REST request using the URL I posted recently, 
which returns a list of countries.  Then I looked at the Glassfish JDBC pool 
monitor.  A PDF of this is attached.  You will see that it says the following:

1. NumConnAcquired, 1 count, Number of logical connection

2. NumConnReleased, 1 count, Number of logical connections released to the pool.

3. NumConnCreated, 8 count, The number of physical connections that were 
created since the last reset.

4. NumConnFree, 8count, The total number of free connections in the pool as of 
the last sampling.

I believe that this is why the minimum pool size is 8; each logical connection 
requires 8 physical connections.

This leads me to believe that this is why the number of connections in my 
connection pool is much larger than what one would expect.  Assuming that 
Tomcat only requires one connection object per query, this implies that 
Glassfish requires 8 times that amount.  So, while a normal pool size for 
Tomcat might be 20 connections, in Glassfish this same activity would require 
160 connections.

In any case, I'm now 100% sure that my program doesn't, and never did, have a 
memory leak.  I have modified my code according to Chris's recommendations, as 
this surely is good advice, but it hasn't changed the performance, since no 
exceptions were ever being thrown. 

It appears to me that Glassfish is performing normally according to its 
internal design, and there really is no problem as long as I keep the maximum 
pool size large enough.

What do you think?

Dan

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

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_count
>> r 
>> ies&d=DwICaQ&c=euGZstcaTDllvimEN8b7jXrwqOf-v5A_CdpgnVfiiMM&r=AbCalLxz
>> o 
>> pgQUG9LLcXdB80OM-GtDfItX76RMxNYqz4&m=NKm1FUayvDzFHyhbqCI0JR32OpW1rfTe
>> d 
>> HFkAoC_xT6Cjqt4-wsVFtYKPtR38vFY&s=4BYNb88ZN6WvyMyyZcR1FyT6Jg-qa4JSDa9
>> P
>> 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.HolidaysRESTJSONResourc
>> e
>> .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

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

Reply via email to