-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Michael,
On 5/7/13 4:33 PM, Michael-O wrote: > Am 2013-05-07 17:20, schrieb Christopher Schultz: >> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 >> >> Michael, >> >> On 5/7/13 6:43 AM, Michael-O wrote: >>>> Von: "Mark Thomas" <ma...@apache.org> On 07/05/2013 10:25, >>>> Michael-O wrote: >>>>> >>>>>> Von: "Mark Thomas" <ma...@apache.org> On 07/05/2013 >>>>>> 09:16, Michael-O wrote: >>>>>>> Hi folks, >>>>>>> >>>>>>> I recently enabled a QueryTimeoutInterceptor with >>>>>>> queryTimeout of 60 seconds in a JDBC Pool data source >>>>>>> (7.0.37). When the app was shut down, Tomcat said: "The >>>>>>> web application [/...] appears to have started a thread >>>>>>> named [OracleTimeoutPollingThread] but has failed to >>>>>>> stop it..." >>>>>>> >>>>>>> We are using Oracle 11.2g with 11.2.0.3 JDBC drivers. >>>>>>> I have figured out that this thread is spawned by the >>>>>>> driver itself. According to this Stackoverflow answer >>>>>>> [1] this is a long-living thread, same says the JDBC >>>>>>> FAQ [2] of Oracle. >>>>>>> >>>>>>> The thread seems to work like Pool's PoolCleaner >>>>>>> thread. A few month a ago I reported the same issue >>>>>>> with the PoolCleaner thread and Filip fixed the class >>>>>>> loader orders. >>>>>>> >>>>>>> Can this be a false-positive by the memory leak >>>>>>> detector since this thread lives only once in the >>>>>>> entire VM? >>>>>> >>>>>> No. It is a memory leak and either or bug in your >>>>>> application or in the JDBC driver. >>>>>> >>>>>> Where is the Oracle JDBC driver? CATALINA_[BASE|HOME]/lib >>>>>> or WEB-INF/lib >>>>> >>>>> The driver is in the $CATALINA_HOME/lib only where >>>>> $CATALINA_BASE != $CATALINA_HOME. This was done for a >>>>> single webapp for testing purposes. >>>>> >>>>> Does this make a difference? >>>> >>>> The important thing is that it isn't in WEB-INF/lib. >>>> >>>>> How do you know that this is not a false-positive? >>>> >>>> Experience, a lot of research into memory leaks and I wrote >>>> Tomcat's memory leak detection code. >>>> >>>>> If you really know for sure, I can open a service request >>>>> with Oracle Support. >>>> >>>> Good luck with that. >>>> >>>> The problem is that when the driver creates the thread it >>>> does so when the current class loader is the web application >>>> class loader. That means that the Thread will be created with >>>> a context class loader set to the web application class >>>> loader. That will trigger a memory leak when the web >>>> application is stopped because a reference is retained to the >>>> web application's class loader. >>>> >>>> What the driver should do is, after it creates the thread, >>>> set the thread's context class loader to the class loader >>>> that loaded the driver. >>>> >>>> What you are seeing is a variation of the leak described on >>>> page 15 of [1]. >>> >>> After reading the slides and your explanation this makes >>> sense. It's the same issue as "Pool cleaner thread should be >>> created using the classloader that loaded the pool, not the >>> context loader (fhanik)" fixed in 7.0.27. >>> >>> I will file SR and let you know. >> >> Note that you might be able to write your own code to mitigate >> this problem, depending on exactly when that thread is created. >> If the timeout thread isn't created until you actually try to >> issue a query with a timeout, try something like this in a >> ServletContextListener's contextInitialized method: >> >> // NOTE: No resource management is being done in this example >> >> // Get the current ClassLoader -- should be WebappClassLoader >> ClassLoader cl = Thread.currentThread().getContextClassLoader(); >> >> // WebappClassLoader.getParent should be "common" loader >> Thread.currentThread().setContextClassLoader(cl.getParent()); >> >> try { Connection conn = ...; // However you get a connection >> Statement s = conn.createStatement(); s.setQueryTimeout(5000); // >> Doesn't really matter what TO is s.execute("SELECT 1 FROM dual", >> ); } .... finally { // Pop back to the original ClassLoader >> Thread.currentThread().setContextClassLoader(cl); } >> >> This is the exact technique that Tomcat's >> JreMemoryLeakPreventionListener uses to prevent ClassLoader >> leaks. > > Yes, this looks like the way JDBC Pool does with the Pool Cleaner. > I would go for this as a last resort. > >> A couple of notes: >> >> 1. This won't work under a SecurityManager. If you need to >> operate under a SecurityManager, have a look at the >> JreMemoryLeakPreventionListener code and adapt it to the above. >> >> 2. If the Oracle driver launches the thread when the DataSource >> is created, it might happen too early for a >> ServletContextListener to intervene. In that case, simply modify >> the JreMEmoryLeakPreventionListener code directly. Patches are >> always welcome. > > Not, it is not. I have attached VisualVM to Tomcat VM and have seen > that the thread is forked when the first query is executed. That's good news: it means that if you need it fixed *right away*, you don't need to hack-and-recompile Tomcat: you can just do it in your own ServletContextListener. >> 3. If Oracle fixes this bug, Tomcat should not prevent against >> it. If Oracle refuses to acknowledge/fix/etc. this bug, then it >> may make sense to include such code in >> JreMemoryLeakPreventionListener, but it should probably be done >> in such a way that a) it's not enabled by default and b) the >> query used for triggering the Thread to be created is >> user-selectable with maybe a reasonable default (like "SELECT 1 >> FROM dual", as that tends to be valid in most RDBMSs). > > I am already in contact with an Oracle engineer who has received a > demo WAR file to reproduce this issue. If Oracle won't, maybe some > generic approach would be advisable but in the in > JreMemoryLeakPreventionListener but rather in Tomcat JDBC Pool > IMHO. I think this might be a rather esoteric thing to exercise, but one could certainly add it as an interceptor that is not enabled by default. > I do not know how other RDBMS vendors implement the timeout > function. MySQL has taken some time to fix similar/related bugs, but is (eventually) willing to fix them: http://bugs.mysql.com/bug.php?id=65909 http://bugs.mysql.com/bug.php?id=36565 - -chris -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.17 (Darwin) Comment: GPGTools - http://gpgtools.org Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQIcBAEBCAAGBQJRiXrJAAoJEBzwKT+lPKRYOqIP/1VeVgEvA82+uAn6x9kSKoQK HN5zOIUwUG/Mr5zWJjR7XeZoOSKaiYHb6xZOjM9zG7hROrHdfrvoj6YLO+GNIe73 wPw9Tx9HGww6NskBYReG/TtS1DKLODsxEd5xkngckDH+xrTr3P0lvhSSpg5pS5c6 gmMqw/PMP6fjvN2JeOtETShxzVYXVX3fh9tYLATPiJuZnMT1v3p0Jo7AZHX7ucRr LnoJm/+VbszQkXq0Bve+FRyE7y4yXgc7J90/FOiJ/B5DJ7a4LQB8jIp88DGFBEKv +s2Yrlf2R39mAtGA1Vj6KEVxvaEW9zIR0wPDuriR6zdxys3kkkYyN51TTkUGOsHA FyFtAlJ0XqAe5oHxeNzW+P+4cn2wzBAz48A6Snhtf8aZoCzRQqJpz9GZfbtF/3YM XLXD9zxpq4r6m61eT8Ai8wh0tz0BDCPDshjh7zD8F99Ov+NGtjI101+Fkkz2J+tM ZDKKWrhfKPXjN47BCYTCw7bM2J9HexJc/Xp9mSr7uI7JaHPcoFPIyH7PJkJLOclZ n4b2SZphYO3WEmyToIWimTupqJIBMYt+jrCC35qOzrSLXUVknA4oWI2IwHjjxNue eoO8Ao6kMlv6+SGKoZGdW+nZCG40tZ7KVPOTPsClZwes/eeOCQrZHnWJCZqZ95qO l9oE3KNfNv1Hu1bjFcyj =oD8m -----END PGP SIGNATURE----- --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org