Dan,

FWIW, I just set up test Glassfish server, and made a trivial app to
acquire and release a connection from the pool.

I configured the connection with a minimum and starting size of 1.

I tested with 1 connection, and it did exactly what I expected. Acquired
and released 1 connection. No more connections were allocated.

The setting for the minimum size is also the initial size (no surprise),
and I could set that value to 1.

My code to acquire the connection was this trivial code:

final InitialContext ic = new InitialContext();
final DataSource ds = (DataSource) ic.lookup("test1");
try (Connection conn = ds.getConnection()) {
} catch (SQLException e) {
  throw new Runtime exception(e);
}

So, I don't agree with your "conclusion" about 8 connections per.

Robert



On Sat, Aug 16, 2025, 00:02 Daniel Schwartz <d...@danielgschwartz.com> wrote:

> Chuck,
>
> Okay, here is the text of the attachment.
>
> Instance Name:
> server
>
>
>
>
> Resource :    HolidaysConnectionPool        Application :
>  HolidaysRESTJSON-1.0-SNAPSHOT
>
> Monitor (14 Statistics)
>  JDBC Connection Pool Statistics : HolidaysConnectionPool
> Name
> Value
> Start Time
> Last Sample Time
> Details
> Description
> NumConnCreated
> 8 count
> Aug 15, 2025 1:26:20 AM
> Aug 15, 2025 1:26:21 AM
> --
> The number of physical connections that were created since the last reset.
> NumConnFree
> 8count
> Aug 15, 2025 1:26:20 AM
> Aug 15, 2025 1:26:21 AM
> High Water Mark: 8 count
> Low Water Mark: 0 count
> The total number of free connections in the pool as of the last sampling.
> NumConnReleased
> 1 count
> Aug 15, 2025 1:26:20 AM
> Aug 15, 2025 1:26:21 AM
> --
> Number of logical connections released to the pool.
> NumPotentialConnLeak
> 0 count
> Aug 15, 2025 1:26:20 AM
> --
> --
> Number of potential connection leaks
> NumConnFailedValidation
> 0 count
> Aug 15, 2025 1:26:20 AM
> --
> --
> The total number of connections in the connection pool that failed
> validation from the start time until the last sample time.
> ConnRequestWaitTime
> 485millisecond
> Aug 15, 2025 1:26:20 AM
> Aug 15, 2025 1:26:21 AM
> High Water Mark: 485 millisecond
> Low Water Mark: 0 millisecond
> The longest and shortest wait times of connection requests. The current
> value indicates the wait time of the last request that was serviced by the
> pool.
> NumConnAcquired
> 1 count
> Aug 15, 2025 1:26:20 AM
> Aug 15, 2025 1:26:21 AM
> --
> Number of logical connections acquired from the pool.
> AverageConnWaitTime
> 485 millisecond
> Aug 15, 2025 1:26:20 AM
> Aug 15, 2025 1:26:33 AM
> --
> Average wait-time-duration per successful connection request
> NumConnDestroyed
> 0 count
> Aug 15, 2025 1:26:20 AM
> --
> --
> Number of physical connections that were destroyed since the last reset.
> NumConnSuccessfullyMatched
> 0 count
> Aug 15, 2025 1:26:20 AM
> --
> --
> Number of connections succesfully matched
> NumConnNotSuccessfullyMatched
> 0 count
> Aug 15, 2025 1:26:20 AM
> --
> --
> Number of connections rejected during matching
> NumConnUsed
> 0count
> Aug 15, 2025 1:26:20 AM
> Aug 15, 2025 1:26:21 AM
> High Water Mark: 1 count
> Low Water Mark: 0 count
> Provides connection usage statistics. The total number of connections that
> are currently being used, as well as information about the maximum number
> of connections that were used (the high water mark).
> WaitQueueLength
> 0 count
> Aug 15, 2025 1:26:20 AM
> --
> --
> Number of connection requests in the queue waiting to be serviced.
> NumConnTimedOut
> 0 count
> Aug 15, 2025 1:26:20 AM
> --
> --
> The total number of connections in the pool that timed out between the
> start time and the last sample time.
>
> Regarding your statement "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.", I have no idea
> hat this means.
>
> Dan
>
> From: Chuck Caldarale <n82...@gmail.com>
> Sent: Friday, August 15, 2025 11:39 PM
> To: Tomcat Users List <users@tomcat.apache.org>
> Subject: Re: [EXTERNAL EMAIL] How to access a REST service
>
> > On 2025 Aug 15, at 22:03, Daniel Schwartz <d...@danielgschwartz.com
> <mailto: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.
> NkdkJdXPPEBannerStart
> Be Careful With This Message
> From (Chuck Caldarale <n82...@gmail.com>)<
> https://godaddy1.cloud-protect.net/email-details/?k=k1&payload=53616c7465645f5f4a8adbed4b5cf7a587f5f4df537a8eaec1a2b42d4d58936018b1ed681a23d9919bf8332d2b6b61429feb03a72599510c1c3ab28d5aaddc506ec4d56aaa261fcb98bd9aad462cad1cc8e2c0a7c87426fd5ac7bd5b6e2701e483c6c0dabfa7863325d5e1cce43460a01fdb3123cef7a62998f33320b7ee6a504f58e005390e8ee17f0cc8754779156e61decfa830f679ecb7c1779d40b153b44dd3c8946f5c5040afad656b12d548292c93d680a4c9c588dd499f91f4d3fe02cd457cde8bab1d939f1dcbfe104966e4bccd617fa2cf6cf872584c675598f814ea3508244febcc34102818eff6415cdd
> >
> Learn More<
> https://godaddy1.cloud-protect.net/email-details/?k=k1&payload=53616c7465645f5f4a8adbed4b5cf7a587f5f4df537a8eaec1a2b42d4d58936018b1ed681a23d9919bf8332d2b6b61429feb03a72599510c1c3ab28d5aaddc506ec4d56aaa261fcb98bd9aad462cad1cc8e2c0a7c87426fd5ac7bd5b6e2701e483c6c0dabfa7863325d5e1cce43460a01fdb3123cef7a62998f33320b7ee6a504f58e005390e8ee17f0cc8754779156e61decfa830f679ecb7c1779d40b153b44dd3c8946f5c5040afad656b12d548292c93d680a4c9c588dd499f91f4d3fe02cd457cde8bab1d939f1dcbfe104966e4bccd617fa2cf6cf872584c675598f814ea3508244febcc34102818eff6415cdd
> >
> Potential Impersonation
> The sender's identity could not be verified and someone may be
> impersonating the sender. Take caution when interacting with this message.
>
> NkdkJdXPPEBannerEnd
>
>
>
> > On 2025 Aug 15, at 22:03, Daniel Schwartz <d...@danielgschwartz.com
> <mailto: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<mailto:
> ch...@christopherschultz.net>>
>
> > Sent: Friday, August 15, 2025 1:07 PM
>
> > To: users@tomcat.apache.org<mailto: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<mailto:
> ch...@christopherschultz.net>>
>
> >> Sent: Friday, August 15, 2025 12:18 PM
>
> >> To: users@tomcat.apache.org<mailto: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<mailto:
> users-unsubscr...@tomcat.apache.org>
>
> >> For additional commands, e-mail: users-h...@tomcat.apache.org<mailto:
> users-h...@tomcat.apache.org>
>
> >>
>
> >>
>
> >> ---------------------------------------------------------------------
>
> >> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org<mailto:
> users-unsubscr...@tomcat.apache.org>
>
> >> For additional commands, e-mail: users-h...@tomcat.apache.org<mailto:
> users-h...@tomcat.apache.org>
>
> >>
>
> >
>
> >
>
> > ---------------------------------------------------------------------
>
> > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org<mailto:
> users-unsubscr...@tomcat.apache.org>
>
> > For additional commands, e-mail: users-h...@tomcat.apache.org<mailto:
> users-h...@tomcat.apache.org>
>
> >
>
> >
>
> > ---------------------------------------------------------------------
>
> > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org<mailto:
> users-unsubscr...@tomcat.apache.org>
>
> > For additional commands, e-mail: users-h...@tomcat.apache.org<mailto:
> users-h...@tomcat.apache.org>
>
>
>
>
>
> ---------------------------------------------------------------------
>
> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org<mailto:
> users-unsubscr...@tomcat.apache.org>
>
> For additional commands, e-mail: users-h...@tomcat.apache.org<mailto:
> users-h...@tomcat.apache.org>
>
>
>

Reply via email to