当前位置: 首页 > article >正文

jvm安全点(五)openjdk17 c++源码垃圾回收之安全点阻塞状态线程在安全点同步中无需调用block函数的详细流程解析

关于阻塞状态线程在安全点同步中无需调用block函数的详细流程解析:


1. 安全点同步入口:SafepointSynchronize::begin()

VM线程调用此函数启动安全点,核心步骤如下:

  • 获取线程锁(Threads_lock:防止新线程启动或旧线程退出。

  • 初始化计数器_waiting_to_block设为当前线程总数,表示需等待阻塞的线程数。

  • 激活安全点(arm_safepoint():设置全局安全点标志,触发线程轮询。

  • 调用synchronize_threads():进入主循环,等待所有线程进入安全点。


2. 同步线程主循环:synchronize_threads()

此函数通过多次迭代检查所有线程状态,直到所有线程进入安全点:

  • 首次遍历构建链表:将所有未进入安全点的线程(thread_not_running(cur_tss) == false)加入链表tss_head

  • 主循环处理未阻塞线程

    cpp

    复制

    下载

    do {// 遍历链表,检查每个线程状态while (cur_tss != NULL) {if (thread_not_running(cur_tss)) {// 从链表中移除该线程,减少still_running计数--still_running;...} else {// 保留在链表中,继续处理...}}
    } while (still_running > 0);
    • 关键点:只有状态仍为运行的线程会保留在链表中,后续可能触发阻塞操作。


3. 状态检查逻辑:thread_not_running()

该函数判断线程是否已处于安全点或无需阻塞:

cpp

复制

下载

bool SafepointSynchronize::thread_not_running(ThreadSafepointState *cur_state) {if (!cur_state->is_running()) return true; // 已非运行cur_state->examine_state_of_thread(...);   // 检查线程状态return !cur_state->is_running();           // 检查后再次确认
}
  • examine_state_of_thread():深入分析线程状态,决定是否需要阻塞。


4. 线程状态分析:examine_state_of_thread()

此函数通过safepoint_safe_with()判断线程是否已安全:

cpp

复制

下载

void ThreadSafepointState::examine_state_of_thread(...) {JavaThreadState stable_state;if (!try_stable_load_state(&stable_state, ...)) return; // 无法获取稳定状态,视为运行中if (safepoint_safe_with(_thread, stable_state)) {account_safe_thread(); // 标记线程为安全return;}// 其他状态需继续运行,直到主动挂起
}
  • safepoint_safe_with():核心判断逻辑,针对阻塞状态线程。


5. 阻塞状态判定:safepoint_safe_with()

此函数明确处理阻塞状态:

cpp

复制

下载

static bool safepoint_safe_with(JavaThread *thread, JavaThreadState state) {switch(state) {case _thread_blocked:// 阻塞状态的线程直接视为安全return true;case _thread_in_native:// 本地方法线程需检查栈可遍历性return ...;default:return false; // 其他状态需进一步处理}
}
  • 阻塞状态(_thread_blocked:直接返回true,无需额外操作。


6. 标记安全线程:account_safe_thread()

当线程被判定为安全时,此函数更新全局状态:

cpp

复制

下载

void ThreadSafepointState::account_safe_thread() {SafepointSynchronize::decrement_waiting_to_block(); // 减少等待计数器if (_thread->in_critical()) {SafepointSynchronize::increment_jni_active_count(); // 处理JNI临界区}_safepoint_safe = true; // 标记线程为安全点安全
}
  • 减少_waiting_to_block:表示该线程已处理完毕。

  • 标记_safepoint_safe:后续检查中is_running()将返回false


7. 阻塞函数的调用条件

在提供的代码中,未直接调用block()函数,但隐含逻辑如下:

  • 需主动阻塞的线程:状态为运行中(如执行Java代码、JNI非临界区),会保留在tss_head链表中,等待后续处理(如轮询触发挂起)。

  • 阻塞状态的线程:因safepoint_safe_with()返回true,被移出链表,不会进入需阻塞的分支。


总结:为何阻塞状态线程无需调用block

  1. 状态判定:通过safepoint_safe_with()识别阻塞状态,直接标记为安全。

  2. 链表移除:在synchronize_threads()循环中,安全线程被移出待处理链表。

  3. 计数器更新_waiting_to_block递减,最终为0时同步完成。

  4. 避免冗余操作:已阻塞线程无需二次挂起,提升效率。

此机制确保安全点同步仅处理必要线程,避免对已阻塞线程的不必要操作。

##源码

// Roll all threads forward to a safepoint and suspend them all
void SafepointSynchronize::begin() {assert(Thread::current()->is_VM_thread(), "Only VM thread may execute a safepoint");EventSafepointBegin begin_event;SafepointTracing::begin(VMThread::vm_op_type());Universe::heap()->safepoint_synchronize_begin();// By getting the Threads_lock, we assure that no threads are about to start or// exit. It is released again in SafepointSynchronize::end().Threads_lock->lock();assert( _state == _not_synchronized, "trying to safepoint synchronize with wrong state");int nof_threads = Threads::number_of_threads();_nof_threads_hit_polling_page = 0;log_debug(safepoint)("Safepoint synchronization initiated using %s wait barrier. (%d threads)", _wait_barrier->description(), nof_threads);// Reset the count of active JNI critical threads_current_jni_active_count = 0;// Set number of threads to wait for_waiting_to_block = nof_threads;jlong safepoint_limit_time = 0;if (SafepointTimeout) {// Set the limit time, so that it can be compared to see if this has taken// too long to complete.safepoint_limit_time = SafepointTracing::start_of_safepoint() + (jlong)SafepointTimeoutDelay * (NANOUNITS / MILLIUNITS);timeout_error_printed = false;}EventSafepointStateSynchronization sync_event;int initial_running = 0;// Arms the safepoint, _current_jni_active_count and _waiting_to_block must be set before.arm_safepoint();// Will spin until all threads are safe.int iterations = synchronize_threads(safepoint_limit_time, nof_threads, &initial_running);assert(_waiting_to_block == 0, "No thread should be running");#ifndef PRODUCT// Mark all threadsif (VerifyCrossModifyFence) {JavaThreadIteratorWithHandle jtiwh;for (; JavaThread *cur = jtiwh.next(); ) {cur->set_requires_cross_modify_fence(true);}}if (safepoint_limit_time != 0) {jlong current_time = os::javaTimeNanos();if (safepoint_limit_time < current_time) {log_warning(safepoint)("# SafepointSynchronize: Finished after "INT64_FORMAT_W(6) " ms",(int64_t)(current_time - SafepointTracing::start_of_safepoint()) / (NANOUNITS / MILLIUNITS));}}
#endifassert(Threads_lock->owned_by_self(), "must hold Threads_lock");// Record state_state = _synchronized;OrderAccess::fence();// Set the new id++_safepoint_id;#ifdef ASSERT// Make sure all the threads were visited.for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur = jtiwh.next(); ) {assert(cur->was_visited_for_critical_count(_safepoint_counter), "missed a thread");}
#endif // ASSERT// Update the count of active JNI critical regionsGCLocker::set_jni_lock_count(_current_jni_active_count);post_safepoint_synchronize_event(sync_event,_safepoint_id,initial_running,_waiting_to_block, iterations);SafepointTracing::synchronized(nof_threads, initial_running, _nof_threads_hit_polling_page);// We do the safepoint cleanup first since a GC related safepoint// needs cleanup to be completed before running the GC op.EventSafepointCleanup cleanup_event;do_cleanup_tasks();post_safepoint_cleanup_event(cleanup_event, _safepoint_id);post_safepoint_begin_event(begin_event, _safepoint_id, nof_threads, _current_jni_active_count);SafepointTracing::cleanup();
}int SafepointSynchronize::synchronize_threads(jlong safepoint_limit_time, int nof_threads, int* initial_running)
{JavaThreadIteratorWithHandle jtiwh;#ifdef ASSERTfor (; JavaThread *cur = jtiwh.next(); ) {assert(cur->safepoint_state()->is_running(), "Illegal initial state");}jtiwh.rewind();
#endif // ASSERT// Iterate through all threads until it has been determined how to stop them all at a safepoint.int still_running = nof_threads;ThreadSafepointState *tss_head = NULL;ThreadSafepointState **p_prev = &tss_head;for (; JavaThread *cur = jtiwh.next(); ) {ThreadSafepointState *cur_tss = cur->safepoint_state();assert(cur_tss->get_next() == NULL, "Must be NULL");if (thread_not_running(cur_tss)) {--still_running;} else {*p_prev = cur_tss;p_prev = cur_tss->next_ptr();}}*p_prev = NULL;DEBUG_ONLY(assert_list_is_valid(tss_head, still_running);)*initial_running = still_running;// If there is no thread still running, we are already done.if (still_running <= 0) {assert(tss_head == NULL, "Must be empty");return 1;}int iterations = 1; // The first iteration is above.int64_t start_time = os::javaTimeNanos();do {// Check if this has taken too long:if (SafepointTimeout && safepoint_limit_time < os::javaTimeNanos()) {print_safepoint_timeout();}p_prev = &tss_head;ThreadSafepointState *cur_tss = tss_head;while (cur_tss != NULL) {assert(cur_tss->is_running(), "Illegal initial state");if (thread_not_running(cur_tss)) {--still_running;*p_prev = NULL;ThreadSafepointState *tmp = cur_tss;cur_tss = cur_tss->get_next();tmp->set_next(NULL);} else {*p_prev = cur_tss;p_prev = cur_tss->next_ptr();cur_tss = cur_tss->get_next();}}DEBUG_ONLY(assert_list_is_valid(tss_head, still_running);)if (still_running > 0) {back_off(start_time);}iterations++;} while (still_running > 0);assert(tss_head == NULL, "Must be empty");return iterations;
}bool SafepointSynchronize::thread_not_running(ThreadSafepointState *cur_state) {if (!cur_state->is_running()) {return true;}cur_state->examine_state_of_thread(SafepointSynchronize::safepoint_counter());if (!cur_state->is_running()) {return true;}LogTarget(Trace, safepoint) lt;if (lt.is_enabled()) {ResourceMark rm;LogStream ls(lt);cur_state->print_on(&ls);}return false;
}void ThreadSafepointState::examine_state_of_thread(uint64_t safepoint_count) {assert(is_running(), "better be running or just have hit safepoint poll");JavaThreadState stable_state;if (!SafepointSynchronize::try_stable_load_state(&stable_state, _thread, safepoint_count)) {// We could not get stable state of the JavaThread.// Consider it running and just return.return;}if (safepoint_safe_with(_thread, stable_state)) {std::cout << "@@@@yym%%%%----myThreadName----safepoint_safe_with----" << _thread->name() << std::endl;account_safe_thread();return;}// All other thread states will continue to run until they// transition and self-block in state _blocked// Safepoint polling in compiled code causes the Java threads to do the same.// Note: new threads may require a malloc so they must be allowed to finishassert(is_running(), "examine_state_of_thread on non-running thread");return;
}static bool safepoint_safe_with(JavaThread *thread, JavaThreadState state) {switch(state) {case _thread_in_native:// native threads are safe if they have no java stack or have walkable stackreturn !thread->has_last_Java_frame() || thread->frame_anchor()->walkable();case _thread_blocked:// On wait_barrier or blocked.// Blocked threads should already have walkable stack.assert(!thread->has_last_Java_frame() || thread->frame_anchor()->walkable(), "blocked and not walkable");return true;default:return false;}
}void ThreadSafepointState::account_safe_thread() {SafepointSynchronize::decrement_waiting_to_block();if (_thread->in_critical()) {// Notice that this thread is in a critical sectionSafepointSynchronize::increment_jni_active_count();}DEBUG_ONLY(_thread->set_visited_for_critical_count(SafepointSynchronize::safepoint_counter());)assert(!_safepoint_safe, "Must be unsafe before safe");_safepoint_safe = true;
}

相关文章:

jvm安全点(五)openjdk17 c++源码垃圾回收之安全点阻塞状态线程在安全点同步中无需调用block函数的详细流程解析

关于阻塞状态线程在安全点同步中无需调用block函数的详细流程解析&#xff1a; 1. 安全点同步入口&#xff1a;SafepointSynchronize::begin() VM线程调用此函数启动安全点&#xff0c;核心步骤如下&#xff1a; 获取线程锁&#xff08;Threads_lock&#xff09;&#xff1a;防…...

C++ 中的 **常变量** 与 **宏变量** 比较

&#x1f50d; C 中的 常变量 与 宏变量 比较 C 中定义不可修改值的方式主要有两种&#xff1a;常变量&#xff08;const/constexpr&#xff09; 和 宏变量&#xff08;#define&#xff09;。它们在机制、类型安全性、作用域和调试支持方面存在显著差异。 ✅ 1. 常变量&#x…...

【C++】控制台小游戏

移动&#xff1a;W向上&#xff0c;S上下&#xff0c;A向左&#xff0c;D向右 程序代码&#xff1a; #include <iostream> #include <conio.h> #include <windows.h> using namespace std;bool gameOver; const int width 20; const int height 17; int …...

配合本专栏前端文章对应的后端文章——从模拟到展示:一步步搭建传感器数据交互系统

对应文章&#xff1a;进一步完善前端框架搭建及vue-konva依赖的使用&#xff08;Vscode&#xff09;-CSDN博客 目录 一、后端开发 1.模拟传感器数据 2.前端页面呈现数据后端互通 2.1更新模拟传感器数据程序&#xff08;多次请求&#xff09; 2.2&#x1f9e9; 功能目标 …...

React中常用的钩子函数:

一. 基础钩子 (1)useState 用于在函数组件中添加局部状态。useState可以传递一个参数&#xff0c;做为状态的初始值&#xff0c;返回一个数组&#xff0c;数组的第一个元素是返回的状态变量&#xff0c;第二个是修改状态变量的函数。 const [state, setState] useState(ini…...

springboot IOC

springboot IOC IoC Inversion of Control Inversion 反转 依赖注入 DI &#xff08;dependency injection &#xff09; dependency 依赖 injection 注入 Qualifier 预选赛 一文带你快速理解JavaWeb中分层解耦的思想及其实现&#xff0c;理解 IOC和 DI https://zhuanlan.…...

java面试每日一背 day2

1.什么是缓存击穿&#xff1f;怎么解决&#xff1f; 缓存击穿是指在高并发场景下&#xff0c;某个热点key突然过期失效&#xff0c;此时大量请求同时访问这个已经过期的key&#xff0c;导致所有请求都直接打到数据库上&#xff0c;造成数据库瞬时压力过大甚至崩溃的情况。 解…...

Ajax01-基础

一、AJAX 1.AJAX概念 使浏览器的XMLHttpRequest对象与服务器通信 浏览器网页中&#xff0c;使用 AJAX技术&#xff08;XHR对象&#xff09;发起获取省份列表数据的请求&#xff0c;服务器代码响应准备好的省份列表数据给前端&#xff0c;前端拿到数据数组以后&#xff0c;展…...

(37)服务器增加ipv6配置方法

(1)172.25.38.93服务器,IPv6地址如下: IPv6地址:2405:6F00:E033:B800:0000:0000:0003:0A5D IPv6掩码:/120 IPv6网关地址:2405:6F00:E033:B800:0000:0000:0003:0AFF 配置: # 静态 IPv6 地址和前缀(根据实际情况填写) IPV6ADDR=2405:6F00:E033:B800:0000:0000:0003:0…...

生成树协议(STP)配置详解:避免网络环路的最佳实践

生成树协议&#xff08;STP&#xff09;配置详解&#xff1a;避免网络环路的最佳实践 生成树协议&#xff08;STP&#xff09;配置详解&#xff1a;避免网络环路的最佳实践一、STP基本原理二、STP 配置示例&#xff08;华为交换机&#xff09;1. 启用生成树协议2. 配置根桥3. 查…...

面向 C 语言项目的系统化重构实战指南

摘要: 在实际开发中,C 语言项目往往随着功能演进逐渐变得混乱:目录不清、宏滥用、冗余代码、耦合高、测试少……面对这样的“技术债积累”,盲目大刀阔斧只会带来更多混乱。本文结合 C 语言的特点,从项目评估、目录规划、宏与内联、接口封装、冗余剔除、测试与 CI、迭代重构…...

网络层——蚂蚁和信鸽的关系VS路由原理和相关配置

前言&#xff08;&#x1f41c;✉️&#x1f54a;️&#xff09; 今天内容的主角是蚂蚁&#xff08;动态路由&#xff09;和信鸽&#xff08;静态路由&#xff09;&#xff0c;为什么这么说呢&#xff0c;来看一则小故事吧。 森林里&#xff0c;森林邮局要送一份重要信件&am…...

Python Pandas库简介及常见用法

Python Pandas库简介及常见用法 一、 Pandas简介1. 简介2. 主要特点&#xff08;一&#xff09;强大的数据结构&#xff08;二&#xff09;灵活的数据操作&#xff08;三&#xff09;时间序列分析支持&#xff08;四&#xff09;与其他库的兼容性 3.应用场景&#xff08;一&…...

第十六届蓝桥杯复盘

文章目录 1.数位倍数2.IPv63.变换数组4.最大数字5.小说6.01串7.甘蔗8.原料采购 省赛过去一段时间了&#xff0c;现在复盘下&#xff0c;省赛报完名后一直没准备所以没打算参赛&#xff0c;直到比赛前两天才决定参加&#xff0c;赛前两天匆匆忙忙下载安装了比赛要用的编译器ecli…...

【已解决】HBuilder X编辑器在外接显示器或者4K显示器怎么界面变的好小问题

触发方式&#xff1a;主要涉及DPI缩放问题&#xff0c;可能在电脑息屏有概率触发 修复方式&#xff1a; 1.先关掉软件直接更改屏幕缩放&#xff0c;然后打开软件&#xff0c;再关掉软件恢复原来的缩放&#xff0c;再打开软件就好了 2.(不推荐&#xff09;右键HBuilder在属性里…...

直线型绝对值位移传感器:精准测量的科技利刃

在科技飞速发展的今天&#xff0c;精确测量成为了众多领域不可或缺的关键环节。无论是工业自动化生产线上的精细操作&#xff0c;还是航空航天领域中对零部件位移的严苛把控&#xff0c;亦或是科研实验中对微小位移变化的精准捕捉&#xff0c;都离不开一款高性能的测量设备——…...

解决服务器重装之后vscode Remote-SSH无法连接的问题

在你的windows命令窗口输入&#xff1a; ssh-keygen -R 服务器IPssh-keygen 不是内部或外部命令 .找到Git(安装目录)/usr/bin目录下的ssh-keygen.exe(如果找不到&#xff0c;可以在计算机全局搜索) 2.属性–>高级系统设置–>环境变量–>系统变量,找到Path变量&#…...

AI 招聘系统科普:如何辨别真智能与伪自动化

一、传统招聘模式的效率困境 在数字化转型浪潮中&#xff0c;传统招聘模式的效率瓶颈日益凸显。以中大型企业为例&#xff0c;HR 约 60% 的工作时间消耗在重复操作上&#xff1a; 职位发布&#xff1a;需在多个渠道手动登录、填写字段&#xff0c;单次耗时超 20 分钟&#xf…...

Ansible模块——管理100台Linux的最佳实践

使用 Ansible 管理 100 台 Linux 服务器时&#xff0c;推荐遵循以下 最佳实践&#xff0c;以提升可维护性、可扩展性和安全性。以下内容结合实战经验进行总结&#xff0c;适用于中大型环境&#xff08;如 100 台服务器&#xff09;&#xff1a; 一、基础架构设计 1. 分组与分层…...

从0开始学习大模型--Day09--langchain初步使用实战

众所周知&#xff0c;一味地学习知识&#xff0c;所学的东西和概念都是空中楼阁&#xff0c;大部分情况下&#xff0c;实战都是很有必要的&#xff0c;今天就通过微调langchain来更深刻地理解它。 中间如何进入到langchain界面请参考结尾视频链接。 首先&#xff0c;进入界面…...

C++中的菱形继承问题

假设有一个问题&#xff0c;类似于鸭子这样的动物有很多种&#xff0c;如企鹅和鱿鱼&#xff0c;它们也可能会有一些共同的特性。例如&#xff0c;我们可以有一个叫做 AquaticBird &#xff08;涉禽&#xff0c;水鸟的一类&#xff09;的类&#xff0c;它又继承自 Animal 和 Sw…...

订单越来越到导致接口列表查询数据缓慢解决思路

文章目录 **一、前期诊断&#xff1a;定位性能瓶颈****1. 数据现状分析****2. 业务场景梳理** **二、基础优化&#xff1a;快速提升性能****1. 索引精准优化****2. 表结构优化&#xff08;垂直分表&#xff09;****3. 读写分离与缓存策略** **三、架构升级&#xff1a;应对千万…...

word格式相关问题

页眉 1 去除页眉横线&#xff1a; 双击打开页眉&#xff0c;然后点击正文样式&#xff0c;横线就没有了。 2 让两部分内容的页眉不一样&#xff1a; 使用“分节符”区分两部分内容&#xff0c;分节符可以在“布局-分隔符”找到。然后双击打开页眉&#xff0c;取消“链接到前一…...

网络-MOXA设备基本操作

修改本机IP和网络设备同网段&#xff0c;输入设备IP地址进入登录界面&#xff0c;交换机没有密码&#xff0c;路由器密码为moxa 修改设备IP地址 交换机 路由器 环网 启用Turbo Ring协议&#xff1a;在设备的网络管理界面中&#xff0c;找到环网配置选项&#xff0c;启用Turb…...

飞桨paddle import fluid报错【已解决】

跟着飞桨的安装指南安装了paddle之后 pip install paddlepaddle有一个验证&#xff1a; import paddle.fluid as fluid fluid.install check.run check()报错情况如下&#xff0c;但是我在pip list中&#xff0c;确实看到了paddle安装上了 我import paddle别的包&#xff0c…...

测试工程师要如何开展单元测试

单元测试是软件开发过程中至关重要的环节&#xff0c;它通过验证代码的最小可测试单元(如函数、方法或类)是否按预期工作&#xff0c;帮助开发团队在早期发现和修复缺陷&#xff0c;提升代码质量和可维护性。以下是测试工程师开展单元测试的详细步骤和方法&#xff1a; 一、理…...

IPv4 地址嵌入 IPv6 的前缀转换方式详解

1. 概述 在 IPv4 和 IPv6 网络共存的过渡期&#xff0c;NAT64&#xff08;Network Address Translation 64&#xff09;是一种关键技术&#xff0c;用于实现 IPv6-only 网络与 IPv4-only 网络的互操作。NAT64 前缀转换通过将 IPv4 地址嵌入到 IPv6 地址中&#xff0c;允许 IPv…...

野火鲁班猫(arrch64架构debian)从零实现用MobileFaceNet算法进行实时人脸识别(三)用yolov5-face算法实现人脸检测

环境直接使用第一篇中安装好的环境即可 先clone yolov5-face项目 git clone https://github.com/deepcam-cn/yolov5-face.git 并下载预训练权重文件yolov5n-face.pt 网盘链接: https://pan.baidu.com/s/1xsYns6cyB84aPDgXB7sNDQ 提取码: lw9j &#xff08;野火官方提供&am…...

IS-IS 中间系统到中间系统

前言&#xff1a; 中间系统到中间系统IS-IS&#xff08;Intermediate System to Intermediate System&#xff09;属于内部网关协议IGP&#xff08;Interior Gateway Protocol&#xff09;&#xff0c;用于自治系统内部 IS-IS也是一种链路状态协议&#xff0c;使用最短路径优先…...

【图像生成大模型】HunyuanVideo:大规模视频生成模型的系统性框架

HunyuanVideo&#xff1a;大规模视频生成模型的系统性框架 引言HunyuanVideo 项目概述核心技术1. 统一的图像和视频生成架构2. 多模态大语言模型&#xff08;MLLM&#xff09;文本编码器3. 3D VAE4. 提示重写&#xff08;Prompt Rewrite&#xff09; 项目运行方式与执行步骤1. …...