> 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