> On 2025 Aug 15, at 22:03, Daniel Schwartz <d...@danielgschwartz.com> wrote:
> 
> 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.


The list strips nearly all attachments, for safely reasons. You need to post 
the text.


>  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.


I think that is extremely unlikely. What is more likely is that the GlassFish 
connection pool simply initializes the configured minimum number of connections 
on the first attempt to acquire a connection.

You can test this by making concurrent requests and seeing what happens to the 
pool counters. Try inserting a delay in your code between opening a connection 
and closing it; something like Thread.currentThread().sleep(10000) would likely 
suffice. Then initiate independent requests from several browser tabs in 
parallel; the 10-second delay should allow time for each request to grab its 
own connection from the pool while the other requests are still active.


> 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.


Did you apply the try-catch-finally pattern to all DB-related objects, such as 
statements, prepared statements, and result sets?

  - Chuck


> 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


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

Reply via email to