max wrote:
yes we know finalize() is bad (as per gavins blog), and the question is wether the safeguard is worth the price.
until now it has been worthwhile ensuring connections are getting closed...
One comment before I post a benchmark ... I would be happy if someone could provide a "SafeConnectionManager" vs. an "Unsafe" one via properties or something. If I can pick and choose that would be fine, and you guys could keep the safety built into the loads.
Anyways ....
I just want to use the standard disclaimer about how micro benchmarks are bad. I know they are, and that was the source of my original reluctance to do this, but it seems the onus is on me to prove the problem exists. I'm surrpised that the Hibernate team doesn't have a suite of benchmarks that would support this, but in any case.
I wrote something that did simple writes only to an HSQL database, based on the cats example from the quickstart. I constrained the heap to get some fast GC results, and am using the concurrent mark and sweep collector. Some maybe relevant stats on my pc ...
- Java 1.5.0_Update 5
- HSQL - v1.7.3
- Windows 2000, Pentium 1.8, 1 Gb RAM
Run with finalizer:
D:\temp\hibernate>java -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -verbose:gc -Xloggc:hibernategc.log -Xmx48m -cp .;.\lib\hibernate3.jar;.\
lib\antlr-2.7.5H3.jar;.\lib\asm.jar;.\lib\cglib-2.1.jar;.\lib\commons-collections-2.1.1.jar;.\lib\commons-logging-1.0.4.jar;.\lib\dom4j-1.6.
jar;.\lib\ehcache-1.1.jar;.\lib\hsqldb.jar;.\lib\jta.jar PauseTest 60000
Starting test.
Time to complete test: 58656ms.
Longest weak reference impact in log: 0.0989011 secs
Run without finalizer:
D:\temp\hibernate>java -XX:+UseConcMarkSweepGC -verbose:gc -Xloggc:hibernategc.log -Xmx48m -cp .;.\patch\NoFinalizeConnectionManager.jar;.\l
ib\hibernate3.jar;.\lib\antlr-2.7.5H3.jar;.\lib\asm.jar;.\lib\cglib-2.1.jar;.\lib\commons-collections-2.1.1.jar;.\lib\commons-logging-1.0.4.
jar;.\lib\dom4j-1.6.jar;.\lib\ehcache-1.1.jar;.\lib\hsqldb.jar;.\lib\jta.jar PauseTest 60000
Starting test.
Time to complete test: 41111ms.
Longest weak reference impact in log: *None*
Why is this ?... I believe the concurrent collector never needs to go to the long collection, which helps the throughput as much as it does. Here is the code, if I'm doing something wrong can someone please point it out to me ? I ran this run a couple of times to try and generate a long pause, and I just couldn't do it.
Is that what you guys needed ?
Code:
import org.hibernate.*;
import org.hibernate.cfg.Configuration;
import java.util.logging.*;
/**
* A simple test class to demonstrate pause times in hibernate due
* to finalizers. Based on the simple cats example in the quickstart
* guide using Hypersonic as a database.<p>
*/
public class PauseTest {
/**
*Empty Constructor.<p>
*/
public PauseTest(){
Level newLevel =Level.SEVERE; // We still want to log errors
Logger tmpLogger = java.util.logging.Logger.getLogger("org.hibernate");
tmpLogger.setLevel(newLevel);
}
/**
* Create the session factory for this test.<p>
*
*/
public SessionFactory getSessionFactory(){
Configuration configuration = new Configuration()
.setProperty("hibernate.hbm2ddl.auto","update")
.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect")
.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver")
.setProperty("hibernate.connection.url","jdbc:hsqldb:mem:test")
.setProperty("hibernate.connection.username", "sa")
.setProperty("hibernate.connection.pool_size", "1")
.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.HashtableCacheProvider")
.setProperty("hibernate.show_sql", "false")
.addClass(Cat.class);
return configuration.buildSessionFactory();
}
/**
* Starts the test routine.<p>
* @param n The number of iterations.
*/
public void start(int n) throws Exception {
SessionFactory factory = getSessionFactory();
Session session = null;
for (int i=0 ;i<n; i++) {
try {
session = factory.openSession();
Cat princess = new Cat();
princess.setName("Princess"+i);
princess.setSex('F');
princess.setWeight(7.4f);
session.save(princess);
session.flush();
session.connection().commit();
} catch (HibernateException he) {
he.printStackTrace();
}
finally {
session.close();
}
}
}
/**
* Start the pause test.<p>
*
*/
public static void main(String[] args) throws Exception{
long timeStamp = System.currentTimeMillis();
PauseTest aTest = new PauseTest();
System.out.println("Starting test.");
if (args[0] !=null){
aTest.start(Integer.parseInt(args[0]));
}else {
aTest.start(200);
}
long delta = System.currentTimeMillis() - timeStamp;
System.out.println("Time to complete test: "+delta+" ms.");
}
}