`

java vm死锁分析

阅读更多

一. 如何检测死锁的根源
    Java并不提供对死锁的检测机制。笔者认为常用分析Java代码问题的最有效的工具仍然是java thread dump。当死锁发生时,JVM通常处于挂起状态,thread dump可以给出静态稳定的信息,查找死锁只需要查找有问题的线程。Java虚拟机死锁发生时,从操作系统上观察,虚拟机的CPU占用率为零,很快会从 top或prstat的输出中消失。这时可以收集thread dump,查找"waiting for monitor entry"的thread,如果大量thread都在等待给同一个地址上锁(因为对于Java,一个对象只有一把锁),这说明很可能死锁发生了。

    为了确定问题,笔者建议在隔几分钟后再次收集一次thread dump,如果得到的输出相同,仍然是大量thread都在等待给同一个地址上锁,那么肯定是死锁了。如何找到当前持有锁的线程是解决问题的关键。一般方 法是搜索thread dump,查找"locked,找到持有锁的线程。如果持有锁的线程还在等待给另一个对象上锁,那么还是按上面的办法顺藤摸瓜,直到找到死锁的根源为止。

    另外,在thread dump里还会经常看到这样的线程,它们是等待一个条件而主动放弃锁的线程。有时也需要分析这类线程,尤其是线程等待的条件。

二 几种常见死锁及对策
    解决死锁没有简单的方法,这是因为线程产生死锁都各有各的原因,而且往往具有很高的负载。大多数软件测试产生不了足够多的负载,所以不可能暴露所有的线程错误。在这里中,笔者将讨论开发过程常见的4类典型的死锁和解决对策。

  (1)数据库死锁
  在数据库中,如果一个连接占用了另一个连接所需的数据库锁,则它可以阻塞另一个连接。如果两个或两个以

上的连接相互阻塞,则它们都不能继续执行,这种情况称为数据库死锁。

  数据库死锁问题不易处理,通常数据行进行更新时,需要锁定该数据行,执行更新,然后在提交或回滚封闭事务时释放锁。由于数据库平台、配置的隔离级以及 查询提示的不同,获取的锁可能是细粒度或粗粒度的,它会阻塞(或不阻塞)其他对同一数据行、表或数据库的查询。基于数据库模式,读写操作会要求遍历或更新 多个索引、验证约束、执行触发器等。每个要求都会引入更多锁。此外,其他应用程序还可能正在访问同一数据库模式中的某些对象,并获取不同应用程序所具有的 锁。

  所有这些因素综合在一起,数据库死锁几乎不可能被消除了。值得庆幸的是,数据库死锁通常是可恢复的:当数据库发现死锁时,它会强制销毁一个连接(通常 是使用最少的连接),并回滚其事务。这将释放所有与已经结束的事务相关联的锁,至少允许其他连接中有一个可以获取它们正在被阻塞的锁。

由于数据库具有这种典型的死锁处理行为,所以当出现数据库死锁问题时,数据库常常只能重试整个事务。当数据库连接被销毁时,会抛出可被应用程序捕获的异 常,并标识为数据库死锁。如果允许死锁异常传播到初始化该事务的代码层之外,则该代码层可以启动一个新事务并重做先前所有工作。

  当出现问题就重试,由于数据库可以自由地获取锁,所以几乎不可能保证两个或两个以上的线程不发生数据库死锁。此方法至少能保证在出现某些数据库死锁情况时,应用程序能正常运行。

(2)资源池耗尽死锁

  客户端的增加导致资源池耗尽死锁是由于负载而造成的,即资源池太小,而每个线程需要的资源超过了池中的可用资源。假设连接池最多有10个连接,同时有 10个对外部并发调用。这些线程中每一个都需要一个数据库连接用来清空池。现在,每个线程都执行嵌套的调用。则所有线程都不能继续,但又都不放弃自己的第 一个数据库连接。这样,10个线程都将被死锁。

  研究此类死锁,会发现线程存储中有大量等待获取资源的线程,以及同等数量的空闲且未阻塞的活动数据库连接。当应用程序死锁时,如果可以在运行时检测连接池,就能确认连接池实际上已空。

  修复此类死锁的方法包括:增加连接池的大小或者重构代码,以便单个线程不需要同时使用很多数据库连接。或者可以设置内部调用使用不同的连接池,即使外部调用的连接池为空,内部调用也能使用自己的连接池继续。

  (3)单线程、多冲突数据库连接死锁

  对同一线程执行嵌套的调用有时出现死锁,此情形即使在非高负载系统中通常也会发生。当第一个(外部)连接已获取第二个(内部)连接所需要的数据库锁, 则第二个连接将永久阻塞第一个连接,并等待第一个连接被提交或回滚,这就出现了死锁情形。因为数据库没有注意到两个连接之间的关系,所以数据库不会将此情 形检测为死锁。这样即使不存在并发,此代码也将导致死锁。此情形有多种具体的变种,可以涉及多个线程和两个以上的数据库连接。

  (4)Java虚拟机锁与数据库锁冲突

  这种情形发生在数据库锁与Java虚拟机锁并存的时候。在这种情况下,一个线程占有一个数据库锁并尝试获取Java虚拟机锁。同时,另一个线程占有 Java虚拟机锁并尝试获取数据库锁。此时,数据库发现一个连接阻塞了另一个连接,但由于无法阻止连接继续,所以不会检测到死锁。Java虚拟机发现同步 的锁中有一个线程,并有另一个尝试进入的线程,所以即使Java虚拟机能检测到死锁并对它们进行处理,它还是不会检测到这种情况。

  总而言之,JAVA应用程序中的死锁是一个大问题——它能导致整个应用程序慢慢终止,还很难被分离和修复,尤其是当开发人员不熟悉如何分析死锁环境的时候。

分享到:
评论

相关推荐

    visual vm虚拟机相关分析。

    3. **线程分析**:Visual VM提供线程的详细视图,显示线程状态、阻塞原因以及死锁检测,帮助调试多线程问题。 4. **方法和类的性能分析**:可以追踪方法调用和类加载,了解哪些代码段执行时间较长,优化性能关键...

    java虚拟机 1.4

    Java虚拟机(JVM)是Java编程语言的核心组成部分,它为Java程序提供了运行环境,使得Java代码能够在不同的操作系统上“一次编写,到处运行”。在Java虚拟机1.4的时代,这是Java技术发展的一个重要里程碑,引入了许多...

    用在MyEclipse的VM插件

    总之,MyEclipse的VM插件是Java开发者不可或缺的工具,它强化了MyEclipse对JVM的支持,使开发者能够更好地管理和优化Java应用,提高开发效率和软件质量。结合Velocity这样的模板引擎,可以进一步提升Web应用开发的...

    JNI层创建的线程中回调java方法

    2. **使用JavaVM**:JavaVM是对整个JVM的引用,可以用来获取JNIEnv,同时也可以用来控制JVM的行为,如附加或分离线程。在JNI初始化时,JavaVM指针会作为参数传入,我们可以保存它以便后续使用。 回调Java方法还需要...

    java写的java虚拟机

    `com.tool.javavm`可能是一个Java项目的源代码包,其中包含了JVM的一些基础工具或者组件。这个包通常包含用于解析、加载、执行字节码的类和方法,可能还包括垃圾收集、内存管理、线程调度等JVM的关键功能。 `...

    Visual VM1.3.6

    Visual VM是一款强大的Java性能分析工具,它为开发者提供了一种可视化的方式来监控和分析JVM(Java虚拟机)上的应用程序。1.3.6是Visual VM的一个版本,它包含了许多改进和增强,使得开发者能够更有效地理解和优化...

    Java性能监控工具

    在Java中,有一些内置的工具可以用来监控和分析性能,包括内存使用、垃圾回收等方面。 首先,`jps`命令类似于Linux的`ps`命令,用于列出本地正在运行的Java进程ID。`jstat`工具则可以提供虚拟机(VM)的各种统计...

    VisualVM 免费下载

    VisualVM是一个功能强大的Java虚拟机(JVM)监控、分析和故障排查工具,它提供了广泛的监控和分析功能,可帮助开发人员诊断和解决Java应用程序的性能问题。 主要功能: 1.CPU监控:显示Java进程的CPU使用率、线程...

    JConsole(观察分析Java程序的运行)

    5. **VM摘要**:显示Java虚拟机的详细信息,包括JVM版本、命令行参数等。 6. **MBeans**:显示管理Bean(MBeans)的信息,这是JMX的核心组件之一,用于监控和管理资源。 #### 六、案例分析 1. **内存分析**:通过...

    jprofiler java内存监控

    JProfiler是一款强大的Java性能分析工具,它提供了全面的内存监控、线程分析以及CPU性能剖析等功能,帮助开发者深入理解应用程序的运行状态,找出潜在的性能瓶颈。 ### JProfiler的功能特性 1. **内存分析**:...

    JAVA高级工程师2

    在“JAVA高级工程师2”这一主题中,我们将深入探讨Java编程语言在安全、多线程、图形用户界面(GUI)开发、游戏制作、网络设计以及虚拟机(VM)参数优化等多个核心领域的高级知识。虽然IO(输入/输出)部分涉及较少...

    Java开发常用指令大全.zip

    `jstack`用于打印Java进程的线程堆栈信息,有助于定位死锁或线程阻塞的问题。 10. **jinfo**:配置信息工具 `jinfo`可以查看或修改Java进程的系统属性和命令行选项。 11. **jcmd**:Java诊断命令 自Java 8开始...

    Java虚拟机笔记.pdf

    在Java开发中,理解和优化JVM的性能至关重要,因此需要一些工具来帮助分析JVM的行为: - **jstack**:用于生成当前时刻线程快照,用于定位线程死锁、运行状态等问题。 - **jmap**:用于生成堆内存的快照,可以分析...

    2008JAVA工程师高级培训教程8

    在这个"2008JAVA工程师高级培训教程8"中,重点显然集中在Java的安全性、线程管理、图形界面编程、游戏开发以及网络设计和虚拟机(VM)参数调整。尽管IO(输入/输出)部分涉及较少,但这些核心主题对于一个Java开发者...

    Java监控工具.pdf

    6. **jstack**: jstack 用于生成Java线程的堆栈跟踪,帮助诊断线程阻塞或死锁等问题。通过`jstack process_id`,你可以看到每个线程当前的状态和调用堆栈。 7. **jstat**: jstat 提供了GC和类装载的统计信息,用于...

    java troubleshooting guide for HP-UX.pdf

    ###### 1.5.2 gdb Subcommands for Java VM Debugging (用于Java VM调试的gdb子命令) - **功能**:提供了一系列专门针对Java虚拟机调试的命令。 - **应用场景**:在深入分析Java程序内部机制时必不可少。 ##### 1.6...

    Java Performance Tuning

    这些不同版本的VM可能在内存管理、垃圾收集、编译优化等方面存在差异,因此了解它们的特性对优化至关重要。 书中会遵循一定的编写约定,例如使用特定的术语和符号来帮助读者理解复杂的概念。作者可能还会提供代码...

    VisualVM入门指南 使用说明 新手上路

    - **死锁检测**:检查是否存在线程死锁的情况。 - **线程堆栈跟踪**:查看特定线程的堆栈跟踪信息。 ##### 4.4 查看CPU消耗情况 - **CPU使用率**:监控Java应用的整体CPU使用率。 - **线程CPU使用**:分析各个线程...

    阿里内部资料--Java开发杂项

    ### 阿里内部资料——Java开发杂项:多线程并发详解 ...以上内容不仅涵盖了Java开发中多线程并发的具体实践,还涉及了远程调试、性能监控、线程分析等高级主题,为Java开发者提供了全面的技术指南。

Global site tag (gtag.js) - Google Analytics