Dan,

What's your thread pool size?

With the default of 5, I can never get the high watermark for the
connection above 5 (as I would expect). If I bump up the thread pool max
size, and decrease the maximum db connection pool size, I can then get
connections to queue, etc.

They behave exactly as I would expect and I can never trigger a message
about being unable to obtain a connection.

I added a sleep of 200ms in the previous code I shared while holding the
connection to simulate being slow.

Everything worked without issue. I can fire thousands of connections at it
with no running out of connection problems. Requests queue up and wait for
a connection to be released.

There must be something wrong with how you are managing and using the
connections.

Could you provide a sample of the code that uses the connection?

Robert

On Sat, Aug 16, 2025, 00:35 Robert Turner <rtur...@e-djuster.ca> wrote:

> 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