安全点
安全点是JVM在执行过程中可以安全地暂停所有应用线程的特定位置。在达到安全点时,所有线程会被挂起(暂停)。
以GC过程中 stop the world 的安全点举例:
工作流程:
- 线程挂起:在达到安全点时,所有线程会被挂起(暂停),以便垃圾回收器可以安全地访问并修改对象的引用关系。
- 垃圾回收:在所有线程都暂停后,垃圾回收器开始工作,识别并回收不再被引用的对象。
- 线程恢复:垃圾回收完成后,线程被恢复执行。
实现方式:
- 循环中的安全点:在循环的末尾设置安全点,因为循环通常是执行时间较长的操作。
- 方法调用:在方法调用的返回点设置安全点。
- 异常处理:在异常处理代码中设置安全点。
JVM进入安全点的场景:
- 垃圾回收(GC):stop the world 进行垃圾回收时
- 线程栈的Dump:当需要生成线程栈的快照(如生成线程Dump用于诊断问题)时,JVM需要确保线程的状态是稳定的,因此会进入安全点。
- 类卸载:在某些情况下,JVM可能需要卸载不再使用的类。为了安全地卸载类,JVM会暂停线程进入安全点。
- synchronized锁升级的过程:偏向锁升级为轻量级锁时,JVM可能会选择在安全点进行,以确保锁状态的一致性;当轻量级锁(如偏向锁或自旋锁)升级为重量级锁(操作系统级别的互斥锁)时,JVM可能需要进入安全点来协调线程的状态。
- 调试和性能监控:某些调试操作或性能监控工具可能需要线程在安全点暂停,以便获取一致的程序状态。
安全区域
安全区域是指线程在某段代码中不需要被暂停,因为它不会影响垃圾回收的执行。这通常发生在线程处于某种休眠状态或不执行任何可能改变内存状态的操作时。
场景:
- 线程休眠状态:当线程进入休眠状态,如调用Thread.sleep()、Object.wait()或Thread.join()时,它们不执行任何可能改变内存状态的操作,因此可以被视为处于安全区域。
- 阻塞I/O操作:线程在执行阻塞I/O操作时,例如读取或写入文件、网络通信等,由于线程在等待I/O操作完成期间不会访问或修改堆内存,因此也可以被视为处于安全区域。
- 显式挂起:当线程被显式挂起,例如通过某种同步机制(如锁、信号量)导致线程等待时,它们也可以被视为处于安全区域。
- 无堆内存访问的代码段:某些代码段不涉及堆内存的访问或修改,例如纯计算操作或只访问栈上数据的操作。这些代码段可以被视为安全区域。