站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2EE 专题性能问题,帮忙看看。

性能问题,帮忙看看。

摘要: 性能问题,帮忙看看。


我终于找到了出问题的线程了。

通过thread dump 我发现如下线程一直在运行:
"resin-tcp-connection-*:80-6075" daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable [0x82dfe000..0x82dff19c]
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:103)
at org.logicalcobwebs.proxool.AbstractProxyStatement.testException(AbstractProxyStatement.java:65)
at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:146)
at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
at $java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close()
at com.tag.db.doEndTag(valuetag.java:438)
at _jsp._rst._eng_0aa__jsp._jspService(_products_0viewinfo__jsp.java:75)
at com.caucho.jsp.JavaPage.service(JavaPage.java:60)
at com.caucho.jsp.Page.pageservice(Page.java:570)
at com.caucho.server.dispatch.PageFilterChain.doFilter(PageFilterChain.java:159)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:229)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:267)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:388)
- locked <0x5c472008> (a java.lang.Object)
at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:490)
at com.caucho.util.ThreadPool.run(ThreadPool.java:423)
at java.lang.Thread.run(Thread.java:595)

然后我又查看了顶级的代码调用
at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)
也就是testException这个方法一直在执行,我不清楚为什么为会出现如此死循环。

我想问问大家,什么样的代码会导致proxool的testException一直运行着。



不知道是分数不够,还是人才稀少,怎么就没人回答呢。郁闷


为什么会重复出现:
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
at com.kenfor.exutil.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:152)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:70)
谁能告诉我啊。


本来proxool是很有口碑的连接池 ,怎么会导致

at org.logicalcobwebs.proxool.FatalSqlExceptionHelper.testException(FatalSqlExceptionHelper.java:116)中testException运行没完没了呢。


努力接分升级中...帮你up!


filter 死循环调用?


回复:iihero(阿黑哥)

应该不是filter的引起的,如果是filter的话,那所有的页面都会很容易进入死循环。


下面就是这个永远不结束的方法,我看了一下源代码,虽然有循环部分,但也不导致死循环,
大伙帮我分析一下,具体是什么原因会导致下面的代码一直执行?
/**
* Test to see if an exception is a fatal one
* @param cpd the definition so we can find out what a fatal exception looks like
* @param t the exception to test
* @param level the recursion level (max 20)
* @return true if it is fatal
*/
protected static boolean testException(ConnectionPoolDefinitionIF cpd, Throwable t, int level) {
boolean fatalSqlExceptionDetected = false;
Iterator i = cpd.getFatalSqlExceptions().iterator();
while (i.hasNext()) {
if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) {
// This SQL exception indicates a fatal problem with this connection.
fatalSqlExceptionDetected = true;
}
}

// If it isn't fatal, then try testing the contained exception
if (!fatalSqlExceptionDetected && level < 20) {
Throwable cause = getCause(t);
if (cause != null) {
fatalSqlExceptionDetected = testException(cpd, cause, level + 1);
}
}

return fatalSqlExceptionDetected;
}


while (i.hasNext()) {
if (t.getMessage() != null && t.getMessage().indexOf((String) i.next()) > -1) {
// This SQL exception indicates a fatal problem with this connection.
fatalSqlExceptionDetected = true;
}
}

t.getMessage() != null这句话不成立的话,就没机会调用i.next()
就死循环了。


在网上大家都对proxool赞赏有加,但是我们的项目出现如此严重的错误,实属不应该,
请兄弟们帮我查明此原因,不让我再去怀疑proxool的过错了,把清白留proxool。


回复:zhmt(不爽你就用分砸我!!!)

t.getMessage() != null不成立,也应该会再次调用i.hasNext()吧


请大伙帮我把铁顶起来,都快两天了,还是没找到答案。


你说的错了,&& 运算是从左到右,左边的不成立,直接就返回false了,不再计算右边的。所以不调用i.next()。

楼主要加强基础。


你可以写个小例子测试一下。


当 t.getMessage() != null不成立时,是“t.getMessage().indexOf((String) i.next()) > -1”没机会执行。不是i.hasNext


回复: zhmt(不爽你就用分砸我!!!)

我还是不明白,t.getMessage() != null这句话不成立的话,就会导致死循环。


就算“t.getMessage().indexOf((String) i.next()) > -1不知道,也不会导致死循环啊。


我上面的那段代码是从proxool中取出来的,如果这么容易就死循环了,那我就要怀疑这个东西的安全性啦。


你的问题的背景是什么啊?
不能光看这一点。


resin-tcp-connection-*:80-6075" daemon prio=1 tid=0x0857aac8 nid=0x7fb0 runnable

这是个守护线程,(daemon),一直运行的话,是很正常的。可能问题不在这里,你的是什么性能问题啊?


好,那我就说说背景 :

我维护的是个网站项目,网站经常服务器cpu 99%,并且上去了就不下来了,开始我就确定是
死循环的问题,但是找不到根据,前两天我用kill -3 pid,每隔5分钟Thread Dump一下,发现
上面的线程一直在虚拟机(JVM)里面运行者。那只有死循环才不会退出的。
我不知道我讲清楚没?


daemon是守护进程,但是不应该不结束。


你确信是这个线程启动后cpu才到100%的吗?


是的。在平时,我找不到这样的线程。


我查了一下它的源码,这个类是用来检查一个异常是否是严重异常,它能一直运行说明你的应用导致了很多sql异常。如果这个pool是经过大家的检验的话,可能你的应用中,哪一部分的sql调用很有问题。


是的,但是很多异常也会有个数量限制啊,可能处理校验的速度慢啊,而不会出现,死循环啊。
在页面上传入的sql语句难免有些问题,我测试过,一般情况下,系统会自动处理的,但是我想在就不明白,什么情况下,什么样的SQL语句会导致死循环。


你看了有多少个这样线程了吗?
可能不是死循环,而是线程结束后又被启动起来。或者是启动了多个这样的线程。
如果不是我感才说的那个死循环的,就不可能出现死循环了(next和hasNext要成对使用才不会死在那,如果只使用hasNext而不使用next,那么iterator是不往下走的,就会死了。)。
另外它的递归调用也不会超过20层,所以也不会死。


我觉得从自己的应用上来改进应该更好。


回复:zhmt(不爽你就用分砸我!!!)

你说的有道理,如果 t.getMessage() ==null的话,就会陷入死循环。

但是我看我们的代码都是按照JDBC规范来写的啊。

下面我贴些原码,帮我看看有什么问题。




public HashMap getdbValue(PoolBean pool) throws Exception
{
if(pool.getLog().isDebugEnabled())
pool.getLog().debug("star getdbValue");

String system_name = pool.getDatabaseInfo().getSystemName();
HashMap result = null;
String temp_sql = createSql();
if(temp_sql == null)
throw new SQLException("not sql statement");

Statement stmt = null;
ResultSet rs = null;
Connection con = null;
try
{
con = pool.getNoInfoConnection();// .getConnection();
con.setReadOnly(true);
stmt = con.createStatement();
rs = stmt.executeQuery(temp_sql);
// rs = stmt.executeQuery(sql);
if (rs != null) {
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
if (rs.next()) {
result = new HashMap();
for (int i = 1; i <= colCount; i++) {
String name = rsmd.getColumnName(i);
name = name.toLowerCase();
String type_name = rsmd.getColumnTypeName(i).toLowerCase();
// System.out.println("field name : " + name + " , type_anme : " + type_name);
if ("text".equals(type_name)) {
//当字段类型为text时,如果直接用rs.getObject(i)取数据,在jtds1.0版本中不能直接取出,改为以下方式即可 2005-07-22 张贵平
String tt_str = rs.getString(i);
// System.out.println("text -- "+tt_str);
if (tt_str == null)
tt_str = "";
else
tt_str = tt_str.trim();
result.put(name.trim(), tt_str);
}
else {
Object obj_value = rs.getObject(i);
if (obj_value instanceof java.lang.String) {
String t_str = null;
if (obj_value == null)
t_str = "";
else
t_str = String.valueOf(obj_value).trim();
result.put(name.trim(), t_str);
}
else {
result.put(name.trim(), obj_value);
}
}
}
}
rsmd = null;
}
rs.close();
stmt.close();
con.setReadOnly(false);
con.close();
}
catch(SQLException e)
{
//CloseCon.Close(con);
pool.getLog().error(system_name+","+e.getMessage()+",sql:"+temp_sql);
throw new SQLException("database perform error : " + e.getMessage());
}
finally
{
CloseCon.Close(con);
}

return result;

}

从线程堆栈上看$java.sql.Statement$$EnhancerByCGLIB$$1a91e2dc.close()
,是从stmt.close()进去的。



觉得不规范
rs.close();
stmt.close();
con.setReadOnly(false);
con.close();

以上这些东西都要放在finnally块中的。

我没用过PoolBean,不知道怎么用,觉得数据库的操作好像没多大问题。你倒网上搜索资料看看吧。


你看下Filter里面的跳转是不是错了。


回复:zhmt(不爽你就用分砸我!!!)

PoolBean 是我们自己写的一个类,主要是做跟连接池的衔接工作。

是的,不是很规范,但是这样也应该不会导致proxool死循环。


我们自己的Filter类,看看有什么问题。

public class SetCharacterEncodingFilter implements Filter {

Log log = LogFactory.getLog(this.getClass().getName());

// ----------------------------------------------------- Instance Variables

/**
* The default character encoding to set for requests that pass through
* this filter.
*/
protected String encoding = null;


/**
* The filter configuration object we are associated with. If this value
* is null, this filter instance is not currently configured.
*/
protected FilterConfig filterConfig = null;

/**
* 上传文件的最大大小
*/
protected int fileMaxLength = 200*1024; //200K

/**
* Should a character encoding specified by the client be ignored?
*/
protected boolean ignore = true;


/**
* Take this filter out of service.
*/
public void destroy() {

this.encoding = null;
this.filterConfig = null;

}


/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*
* @param request The servlet request we are processing
* @param result The servlet response we are creating
* @param chain The filter chain we are processing
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet error occurs
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {

// Conditionally select and set the character encoding to be used

HttpServletRequest t_re = (HttpServletRequest) request;

String re_uri = trimString(t_re.getRequestURI());
String re_host = trimString(t_re.getServerName());
String qu_str = trimString(t_re.getQueryString());


if (re_uri.indexOf(".do") > 0)
{
if (log.isInfoEnabled())
log.info(re_host + re_uri + "?" + qu_str);

try
{

if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
request.setCharacterEncoding(encoding);
}
// Pass control on to the next filter
chain.doFilter(request, response);
}
catch(Exception e)
{
// e.printStackTrace();
String error_mes = e.getMessage();
String strServerName = null;
String strQueryString = null;
String requestUrl = null;
String remoteAddr = null;
String referer = "";
if(error_mes.indexOf("reset")<0 )
{
try {
strServerName = t_re.getServerName();
strQueryString = t_re.getQueryString();
requestUrl = t_re.getRequestURI();
// strQueryString = CodeTransfer.ISOToUnicode(strQueryString);
referer = t_re.getHeader("referer");
remoteAddr = t_re.getRemoteAddr();
}
catch (Exception e1) {}
if (error_mes != null && !"null".equals(error_mes)&& error_mes.length() > 0) {
log.error(",exception:" +
error_mes + strServerName + " , " + strQueryString + " , " +
requestUrl + " , " + referer);
// System.out.println("exception at filter:" +
// error_mes);
}

}
if(log.isInfoEnabled())
log.info(strServerName + " , " + strQueryString+ " , " + requestUrl + " , " + referer);
}

}


/**
* Place this filter into service.
*
* @param filterConfig The filter configuration object
*/
public void init(FilterConfig filterConfig) throws ServletException {

this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
String value = filterConfig.getInitParameter("ignore");
String file_max_length = filterConfig.getInitParameter("file_max_length");
if(file_max_length!=null && file_max_length.length() >0)
{
fileMaxLength = com.kenfor.util.MyUtil.getStringToInt(file_max_length,200)*1024;
}

if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;

}

/**
* Select an appropriate character encoding to be used, based on the
* characteristics of the current request and/or filter initialization
* parameters. If no character encoding should be set, return
* null.
*


* The default implementation unconditionally returns the value configured
* by the encoding initialization parameter for this
* filter.
*
* @param request The servlet request we are processing
*/
protected String selectEncoding(ServletRequest request) {

return (this.encoding);

}
private String trimString(String value)
{
String result = "";
if(value !=null)
result = value.trim();

return result;
}


}




如果真的是proxool,那我应该感到欣慰,如果是我们写的代码不当引起的,但我就真的无地之容了。


呵呵,这个我也搞不清楚,楼主最好把你们的那个poolBean自己测试一下。
能找到那种情况下出那个错误是最好的。

看看循环使用的时候是否也抛出这个异常,如果这样的话就查查哪的问题吧。如果不出错,可能就是sql写的有问题了。


↑返回目录
前一篇: 如何在java中实现动态执行代码(js的eval)的功能?
后一篇: sina的有些调查问卷,参与过后再次参与则提示我已参与过,它是如何记录我的信息的?