`

Derby: Out Of Memory & Update

阅读更多

下面是一堆流水帐 慎入:

 

一. 问题

Java GC 监视方法与工具 中写道,我们的项目出现了Out Of Memory问题。

现在这个问题看来可能是由Derby引发的。

 

项目中使用的derby版本是10.1,而且还是beta版的。Liu同学google到的信息,这个版本有内存泄露:

Bug Fixes of Derby10.2.2

OutOfMemory error on continuous execution of SQL statement

 

10.2.2的release中说修复了这个bug。但由下列描述:

写道
After fixing the original memory leak, I still run into problems on repeated execution of a sql statement. Take the sample program in the bug and run it with a small heap size (4m). After around 80-90K executions an outofmemory error is thrown. I took snapshots of the heap while the program was running but couldn't find anything obviously wrong.
 

看来这个bug貌似修完了还有问题,需要测一下,因为我们要插入190k的数据一次。

 

二. Derby升级

为此我们做了一次Derby的升级。

我们的应用跑在SunAS 8里面,试了一下,按如下步骤升级:

1. 导出以前数据库的表结构和配置信息。

2. 使用10.4的derby创建新数据库。

 

在工程空间里面能够跑起来,可到SunAS 8里面便无法运行。抛出下面的异常:

 

写道
[#|2009-03-30T14:54:54.700+0800|严重|sun-appserver-pe8.0.0_01|javax.enterprise.system.container.web|_ThreadID=10;|WebModule[/psv2]Exception sending context initialized event to listener instance of class com.okidata.common.InitDB
java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:141)
at com.okidata.common.DBConnectionManager.loadDrivers(DBConnectionManager.java:873)
at com.okidata.common.DBConnectionManager.init(DBConnectionManager.java:814)
at com.okidata.common.DBConnectionManager.<init>(DBConnectionManager.java:448)
at com.okidata.common.DBConnectionManager.<clinit>(DBConnectionManager.java:55)
at com.okidata.common.InitDB.contextInitialized(InitDB.java:76)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3659)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4120)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1089)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:760)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1089)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:467)
at org.apache.catalina.startup.Embedded.start(Embedded.java:986)
at com.sun.enterprise.web.WebContainer.start(WebContainer.java:490)
at com.sun.enterprise.web.PEWebContainer.startInstance(PEWebContainer.java:506)
at com.sun.enterprise.web.PEWebContainerLifecycle.onStartup(PEWebContainerLifecycle.java:54)
at com.sun.enterprise.server.ApplicationServer.onStartup(ApplicationServer.java:295)
at com.sun.enterprise.server.PEMain.run(PEMain.java:220)
at com.sun.enterprise.server.PEMain.main(PEMain.java:172)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.apache.commons.launcher.ChildMain.run(ChildMain.java:269)

Caused by: java.lang.SecurityException: Sealing violation loading org.apache.derby.jdbc.InternalDriver : Package org.apache.derby.jdbc is sealed.
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1722)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:904)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1370)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1233)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:302)
at org.apache.derby.iapi.jdbc.JDBCBoot.boot(Unknown Source)
at org.apache.derby.jdbc.EmbeddedDriver.boot(Unknown Source)
at org.apache.derby.jdbc.EmbeddedDriver.<clinit>(Unknown Source)
... 25 more

 

网上有说是load了两个derby.jar,

但我们调查了不是这个原因.

起初我们以为是class的版本不兼容, 以为是SunAS 8的jdk是1.4.0,而derby10.4要求1.5以上了。

 

但是看了一下Derby的官方文档, 10.2.2的Release Notes 有下列描述:

JDK/JDBC support:

* JDKs 1.3, 1.4, 1.5, and 1.6 plus J2ME J2ME/CDC/Foundation Profile
* JSR-169, JDBC 2.1, JDBC 3.0, and JDBC 4.0 support
 

看来这个版本不兼容的问题可以排除了.

 

回头我们再整理思路:

我们的程序有前后台之分, 我们所谓的前台是SunAS, 后台是我们自己的程序.

现在Derby的启动工作由前台来做, 后台使用网络连接的方式访问该数据库.

问题的原因可以肯定是什么地方不兼容了, 因为我们的前后台程序在工程空间中跑, 在tomcat中跑, 没有任何问题,

那么会不会是derby和SunAS不兼容? Liu同学再一次大胆而机敏的建议,

让后台启动derby, 前台通过网络的方式访问数据库如何.

 

尝试之, 正解是也!

 

nnd, 同样的方式, 启动同样Derby, 我们的后台(自己写的一个jar, 然后java -jar)启动没问题.

配置到web.xml里, 作为一个ServletContextListener去执行,我想不是ServletContextListener的限制,

因为在tomcat里面这么做是没有问题的,在contextInitialized可以很好的启动Derby

所以我们最后只好把它定义成"Sun Application Server 8的一个bug"

 

我们都被折腾得够呛, 因为从我们自己的bug, 折腾到derby的bug, 再折腾到SunAS的问题,

这一圈,确实有点绕.  不过还好, 总算成功的给他升了级, 接下来的便是测试结果.

 

 

三. 升级后测试结果.

升级到Derby10.2之后,有提高,但依旧Out Of Memory.

实际环境中, 每小时做一次19W的插入操作, 跑了两天, 他还是挂掉了.

因为堆大小使用的是默认64M, 所以也不确定是某些原因造成内存确实不够(如数据库变大之类), 还是有溢出.

反正也是升级, 还不如升到10.4正式版

 

升级到10.4之后

第一个晚上, Liu同学在他的电脑上,jprofile里,循环跑了180回左右, 搞出了个OOM, 我们很郁闷,

结果后来Liu同学发现这个OOM是jprofile的,

还好, 总算松了口气, 调大内存接着来~

 

让Derby单独一个虚拟机启动, 我们的应用使用默认64M堆大小, 数据库插入到12G左右, 跑了400来回

从jprofile的数据看, 没有内存溢出现象.

 

至此我们的问题总算算是圆满解决.

 

ps. 没有升级以前, 上述环境下内存溢出非常明显, 且与数据库大小有关系, 越大溢出越快, 这也是我们在另一台机器上的测试结果.

 

四. 总结.

Derby10.1在大批量持续插入时候, 有OOM的bug,

解决办法:

1. 优化我们的程序, 要是到对19W的ArrayList在19W的循环里,循环调用trimToSize可不是什么好事,

    即使每次都会remove掉一个元素,而这一切只是为了得到一个打印机列表.

2. 升级Derby.

3. 使用"-Xms256m -Xmx256m" 调大我们应用的堆大小.

分享到:
评论
4 楼 wjason 2010-02-27  
DT1 写道
Caused by: java.lang.SecurityException: Sealing violation loading org.apache.derby.jdbc.InternalDriver : Package org.apache.derby.jdbc is sealed.
查看这个:
http://www.cn-java.com/www1/?action-viewnews-itemid-858

应该是服务器上也有提供Derby,导致与应用中的Derby冲突了。


谢谢你。这个问题我当时真是不知道。今天才知道Sealing violation的原因。

下面是ibm dw上的一个同样的文章
http://www.ibm.com/developerworks/cn/java/l-seal/index.html

下面这段话引自这篇文章中的解决办法章节,我觉得是了解了Sealing violation错误时,容易忽略的一个东西,于是就引了过来

引用

3.升级JDK

虽然JDK1.4现在还只是Beta版,可如果你喜欢这种解决方式的话,你可以安装JDK1.4 beta,在JDK1.4中,这个问题得到了解决。我并不太清楚JDK1.4对这个问题的解决方法,不过我猜想最有可能的方法是对CLASSPATH中Seal过的包进行优先处理,这样用户就无需考虑顺序问题。
3 楼 DT1 2010-02-27  
Caused by: java.lang.SecurityException: Sealing violation loading org.apache.derby.jdbc.InternalDriver : Package org.apache.derby.jdbc is sealed.
查看这个:
http://www.cn-java.com/www1/?action-viewnews-itemid-858

应该是服务器上也有提供Derby,导致与应用中的Derby冲突了。
2 楼 wjason 2009-04-02  
这回总结完了.
1 楼 wjason 2009-04-02  
又有了新进展, 还没整理

相关推荐

Global site tag (gtag.js) - Google Analytics