求斑主置顶!!!Tomcat 服务宕掉,请各位高手帮忙,为何会这样?(小弟快挂...)

xieyj 2005-01-03 04:07:40
小弟同几位同事刚开发完一套系统,现在遇到很头疼的问题,就是 Tomcat 服务宕掉,日志老是报内存溢出。

我们系统的环境是:Tomcat 5.05 + JDK 1.42 + 数据库使用的是连接池
整个系统是使用:jsp + servlet 完成的。
jsp 处理前台静态页, servlet 与 java class 类用于处理业务逻辑与数据库部分。

小弟同我们的同事检查过所有的数据库对象,在使用完后都关闭了的,并且一些大的对象,在用完后都有 set null,这样就排除了数据库连接对象过多导致这种问题的可能。

但是有以下几个疑问:
1、传说中的 java 不是有内存自动回收功能吗?为什么还会有内存溢出这种现象,我们在 server.xml 中已经配置了足够大的 tomcat 与 jvm 虚拟机的内存,500M 以上,难道还不够用?
2、我在测试 jsp 页面时,看到 java 虚拟机的内存老是往上涨,不会降下来,这是怎么一回事,我用了最简单的 jsp 页面做测试,里面就写了一个简单的 out.println,经过几次修改,几次刷新,java 虚拟机的内存居然是直线上升,为什么会这样?
3、另有一个问题,是不是 tomcat 不适合做为商业用途,是不是连接数或并发数多的时候一定会挂?
现在我们系统里才 50 个人在线使用,应该不会挂的那么频繁,现在每天最少挂一次。

百思不得其解,希望同道中人拔刀相助,小弟实在不行了。
...全文
1218 99 打赏 收藏 转发到动态 举报
写回复
用AI写文章
99 条回复
切换为时间正序
请发表友善的回复…
发表回复
cauiot 2005-01-06
  • 打赏
  • 举报
回复
我也曾遇到过类似问题。
我用hibernate进行sybase数据库的对象化,经常在tomcat启动后不久down掉。
后来发现原因是hibernate用了数据库的temp库,而sybase默认temp库空间太小,造成程序阻塞。
扩大临时库空间后,再将程序中要从数据库中读取大量记录的地方修改成读取一定量的记录。这样才把问题解决的。

呵呵,把以前遇到问题写到这里供参考。
xieyj 2005-01-06
  • 打赏
  • 举报
回复
因为刚才一分一个结贴时报错误,说给分数大于回贴数,郁闷,所以就从下到上再试结一次,结果就ok 了,没得到分的朋友不好意思了:)。
xieyj 2005-01-06
  • 打赏
  • 举报
回复
谢谢诸位的涌跃参与,再次感谢!
xxrl 2005-01-06
  • 打赏
  • 举报
回复
给前同僚友情UP!!
aaronyes 2005-01-06
  • 打赏
  • 举报
回复
友情UP
xieyj 2005-01-05
  • 打赏
  • 举报
回复
还有一个疑问:
tomcat 报的内存溢出,是指内存使用数达到 server.xml 配置的数目(java 虚拟机),还是其它.......
xieyj 2005-01-05
  • 打赏
  • 举报
回复
再谢感谢各位!
我们将把这个底层连接更改成如下形式实现:
ctx 对象和 ds 对象作为全局的对象,只是在tomcat 服务启动时创建一次,相信这样性能在一定程度上有所提升。
我们现在使用的 NDataAccess() 对象的确是每次都创建调用的,调用完后使用它的 close() 方法释放里面的对象。
我现在有一个疑问,上面有个朋友提到的 conn 这个对象不需要关闭,是否合理。conn.close();conn = null; 它的实现是将连接放回连接池,还是将连接置为无效连接,也就是在 tomcat 垃圾回收的时候会被回收掉,要真是后面一种情况的话,那性能还没有直接连接 jdbc 好?就起不到连接池本意的作用。
GJA106 2005-01-05
  • 打赏
  • 举报
回复
方法的final只是限制继承类不能继承这个方法,跟创建当前类实例没有什么关系。
bibiye 2005-01-05
  • 打赏
  • 举报
回复
对了,整个方法用final定义还要每次都定位JNDI么?
bibiye 2005-01-05
  • 打赏
  • 举报
回复
THKS GJA106(中文字符)!
GJA106 2005-01-05
  • 打赏
  • 举报
回复
不行的。代码getDS还不是每次都定位JNDI。
通过JNDI得到DataSource,然后把它保存在内存中(HashMap/HashTable/Vector/自定义类,相当于全局变量)都可以,用到的地方从"全局"变量中取出,然后getConnection就可以了,而不是lookup。JNDI在系统运行期间只作一次,除非"全局"变量DataSource已经为null,为null必需重新定位。
bibiye 2005-01-05
  • 打赏
  • 举报
回复
GJA106(中文字符)
对于你的第四点:a.你的数据库连接池处理程序NDataAccess是在什么时候调用的?只创建一次,然后在系统中全局通用?如果在每个需要调用数据库的地方都创建一次,JNDI定位是一件很“漫长”的过程。如下代码ctx=new InitialContext();if(ctx==null) {throw new Exception("没有匹配的服务器环境");} ConnStr = "java:comp/env/jdbc/anlcrmU" ; DataSource ds=(DataSource)ctx.lookup(ConnStr);
如果1秒钟内定位5000~50000次,Tomcat有可能当掉。

如果改成 final方法,而且ctx不去关闭,会不会好些?
public NDataAccess() throws Exception {
String ConnStr = "" ;
Context ctx = null;
try{
ctx=new InitialContext();
if(ctx==null) {
throw new Exception("没有匹配的服务器环境");
}
ConnStr = "java:comp/env/jdbc/anlcrmU" ;
DataSource ds=(DataSource)ctx.lookup(ConnStr);
if(ds==null) {
throw new Exception("没有匹配数据库连接");
}
conn=ds.getConnection();
//用来设置锁超时
if (this.stmt==null)
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
stmt.executeUpdate("SET DEADLOCK_PRIORITY LOW \n SET LOCK_TIMEOUT 10000");
} catch(SQLException ex){
throw new Exception("创建数据库连接对象异常");
}
finally{
if(ctx!=null)
ctx.close();
ctx = null;
}
}

改为:
public NDataAccess() throws Exception {
try{
DataSource ds=getDS();
if(ds==null) {
throw new Exception("没有匹配数据库连接");
}
conn=ds.getConnection();
//用来设置锁超时
if (this.stmt==null)
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
stmt.executeUpdate("SET DEADLOCK_PRIORITY LOW \n SET LOCK_TIMEOUT 10000");
} catch(SQLException ex){
ex.toString();
}
}

static final private DataSource getDS()
{
String ConnStr = "" ;
Context ctx = null;
DataSource ds = null;
try{
ctx=new InitialContext();
if(ctx==null) {
return null;
}
ConnStr = "java:comp/env/jdbc/anlcrmU" ;
ds=(DataSource)ctx.lookup(ConnStr);
return ds;
}catch(Exception ex){
ex.toString();
}
}
GJA106 2005-01-05
  • 打赏
  • 举报
回复
1.jvm内存回收机制不是内存越大就跑得越快,如果系统只使用了100M内存,你分配了500M不见得有多少好处。
2.正常。应用服务器重新编译jsp页面转换成servlet来处理页面信息。一般正式发版的时候应该是经过预编译的,作正式版压力、性能测试也应该在预编译状态下完成。
3. tomcat 也适合做为商业用途。


4.楼主的现象不完成是tomcat的原因
a.你的数据库连接池处理程序NDataAccess是在什么时候调用的?只创建一次,然后在系统中全局通用?如果在每个需要调用数据库的地方都创建一次,JNDI定位是一件很“漫长”的过程。如下代码ctx=new InitialContext();if(ctx==null) {throw new Exception("没有匹配的服务器环境");} ConnStr = "java:comp/env/jdbc/anlcrmU" ; DataSource ds=(DataSource)ctx.lookup(ConnStr);
如果1秒钟内定位5000~50000次,Tomcat有可能当掉。


b.楼主的连接池是Tomcat服务器的吗?一般连接池都有maxActive、maxWait、CapacityIncrement、InitialCapacity、MaxCapacity...等参数,是如何配置的?

c.代码中如果有“死”循环,最好中间有XX毫秒级的休眠时间。如果代码中可能出现死循环,应该给循环一个上限值,当超出上限值时退出循环。

d.数据库连接有没有关闭,应该有日志信息提供参考!特别是在测试阶段。
e......
knight_yl 2005-01-05
  • 打赏
  • 举报
回复
看看db的连接情况就知道有没有没关闭的连接了。

至少大型数据库都有这个功能,我们用过oracle,后来每页都执行几遍,
看看有没有多打开的数据库连接,这样基本解决数据库的问题。

可以写个线程,定时[建议]回收下内存。
System.gc();
SS_ 2005-01-05
  • 打赏
  • 举报
回复
相似的环境,出现过类似的问题,最早用的时候很多连接没close,导致整个网站老是停止,打开服务看apache tomcat服务又没有停,但就是打不开网站,后来把程序整个检查了一遍,ok了,一个月会停1到2次。又改进了连接数据库的class,现在基本很少停了。
xieyj 2005-01-05
  • 打赏
  • 举报
回复
连接倒是没有操作几M或几十M的数据,ok,非常感谢,我们再调整调整 :)
GJA106 2005-01-05
  • 打赏
  • 举报
回复
1.不都是这样,应该是:隔多少时间+内存的使用状态+XX算法=垃圾回收。详细的偶也不知道。

2.几十个连接不会导致内存溢出(你的连接不是操作几M,几十M的数据吧!!!!)。
在设置maxActive或MaxCapacity或最大连接数时,可以调大一点。
xieyj 2005-01-05
  • 打赏
  • 举报
回复
TO:GJA106
谢谢!
有个问题,垃圾回收是何时开始做回收操作呢?
比如我现在设置的 jvm 的内存上限为 300M,是不是快使用到 300M 时,系统才调用的垃圾回收,如果是的话,那么假设同时这个时候有几十个连接并发操作,会导致什么样的后果,是不是内存溢出 .... -__-!
feyge 2005-01-05
  • 打赏
  • 举报
回复
sign
GJA106 2005-01-05
  • 打赏
  • 举报
回复
1.一定要把connection给close掉,close操作是把当前使用connection放回连接池,而不是关闭掉那个连接,这个层次的操作交给实现连接池方去作的。

2.同一时间内创建n多实例、变量、数据,但这不足以把500M的内存给耗掉,要不就是tomcat没得到那500M内存(能确定内存已经分配给jvm了吗)。
加载更多回复(79)

67,515

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧