【问题标题】:Many threads are blocked and memory from old gen not releasing许多线程被阻塞,老一代的内存没有释放
【发布时间】:2017-03-28 20:24:39
【问题描述】:

我正在使用 tomcat 服务器,当我进行线程转储时,我可以看到许多线程被阻塞 (172) 并且其他线程是 IN_NATIVE (27)。几乎许多被阻塞的线程就像下面的微笑一样。有人可以帮助可能是什么原因。我的 8GB OldGen 空间已满。执行 GC 后也不释放。

阻塞线程:

    Thread 22614 - threadId:Thread 22614 - state:BLOCKED
stackTrace:
- java.net.SocketInputStream.socketRead0(java.io.FileDescriptor, byte[], int, int, int) @bci=0 (Compiled frame; information may be imprecise)
- java.net.SocketInputStream.read(byte[], int, int, int) @bci=87, line=152 (Compiled frame)
- java.net.SocketInputStream.read(byte[], int, int) @bci=11, line=122 (Compiled frame)
- org.apache.coyote.http11.InternalInputBuffer.fill(boolean) @bci=59, line=512 (Compiled frame)
- org.apache.coyote.http11.InternalInputBuffer.fill() @bci=2, line=497 (Compiled frame)
- org.apache.coyote.http11.Http11Processor.process(org.apache.tomcat.util.net.SocketWrapper) @bci=263, line=203 (Compiled frame)
- org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(org.apache.tomcat.util.net.SocketWrapper, org.apache.tomcat.util.net.SocketStatus) @bci=96, line=515 (Compiled frame)
- org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run() @bci=130, line=302 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=95, line=1145 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=615 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=745 (Interpreted frame)




Thread 23677 - threadId:Thread 23677 - state:BLOCKED
stackTrace:
- sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
- java.util.concurrent.locks.LockSupport.parkNanos(java.lang.Object, long) @bci=20, line=226 (Compiled frame)
- java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(long) @bci=68, line=2082 (Compiled frame)
- java.util.concurrent.LinkedBlockingQueue.poll(long, java.util.concurrent.TimeUnit) @bci=62, line=467 (Compiled frame)
- org.apache.tomcat.util.threads.TaskQueue.poll(long, java.util.concurrent.TimeUnit) @bci=3, line=86 (Compiled frame)
- org.apache.tomcat.util.threads.TaskQueue.poll(long, java.util.concurrent.TimeUnit) @bci=3, line=32 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.getTask() @bci=141, line=1068 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=26, line=1130 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=615 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=745 (Interpreted frame)


Thread 23674 - threadId:Thread 23674 - state:BLOCKED
stackTrace:
- com.mysql.jdbc.SingleByteCharsetConverter.toString(byte[], int, int) @bci=1, line=322 (Compiled frame)
- com.mysql.jdbc.ResultSetRow.getString(java.lang.String, com.mysql.jdbc.MySQLConnection, byte[], int, int) @bci=54, line=797 (Compiled frame)
- com.mysql.jdbc.ByteArrayRow.getString(int, java.lang.String, com.mysql.jdbc.MySQLConnection) @bci=24, line=72 (Compiled frame)
- com.mysql.jdbc.ResultSetImpl.getStringInternal(int, boolean) @bci=155, line=5699 (Compiled frame)
- com.mysql.jdbc.ResultSetImpl.getString(int) @bci=3, line=5576 (Compiled frame)
- com.mysql.jdbc.ResultSetImpl.getString(java.lang.String) @bci=6, line=5616 (Compiled frame)
- com.mchange.v2.c3p0.impl.NewProxyResultSet.getString(java.lang.String) @bci=19, line=3342 (Compiled frame)
- org.hibernate.type.StringType.get(java.sql.ResultSet, java.lang.String) @bci=2, line=41 (Compiled frame)
- org.hibernate.type.NullableType.nullSafeGet(java.sql.ResultSet, java.lang.String) @bci=3, line=184 (Compiled frame)
- org.hibernate.type.NullableType.nullSafeGet(java.sql.ResultSet, java.lang.String, org.hibernate.engine.SessionImplementor, java.lang.Object) @bci=3, line=210 (Compiled frame)

【问题讨论】:

  • 嗯,线程转储似乎并不准确。 Unsafe.park 是 TIMED_WAITING,socket.read 是 WAITING。你能通过kill -3 <tomcat_pid> 生成一个线程转储吗?它将包括阻塞线程的对象的地址,因此您可以检查是否存在死锁。

标签: multithreading tomcat7 dump thread-dump


【解决方案1】:
  • 第一个堆栈跟踪表明线程尝试从套接字读取并进入BLOCKED 状态。 Socket读取操作是阻塞操作,意思是如果没有什么要读取或者直到所有信息都读完,它就会阻塞。

  • 其次,LinkedBlockingQueue.poll() 不是阻塞操作,因此这是一个正常的堆栈跟踪,用于指示通常的空闲线程。这不是用户代码造成的

  • 第三,这看起来也没有问题,因为返回了结果集中的字符串值。

我想,你也应该看看this

堆栈跟踪 #1 和 #3 可能相关,因为套接字读取可能是 DB 读取。

这些堆栈跟踪无助于解决问题,但这类阻塞线程仅表明内存过多和垃圾收集过多的问题。

您的 C3P0 池或创建语句和结果集对象的方式可能存在问题 - 总而言之,这似乎是内存泄漏和资源关闭不善的情况。

如果没有相关的应用程序代码,就不可能得到非常精确的答案。此外,正如评论中所述,锁定对象的身份也需要转储。

希望对你有帮助!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-27
    • 2022-01-17
    • 1970-01-01
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多