2024-4-10 群讨论:JFR 热点方法采样实现原理

以下来自本人拉的一个关于 Java 技术的讨论群。关注公众号:hashcon,私信拉你

什么是 JFR 热点方法采样,效果是什么样子?

其实对应的就是 jdk.ExecutionSample 和 jdk.NativeMethodSample 事件

57929a0c3ccd34a8ea2b041a603f5051.jpeg

c108e30ed2e9e20f6ce3641b807f51b3.jpeg

76c70305c49e63f72941d5e2ee2b128b.jpeg

这两个事件是用来采样的,采样的频率是可以配置的,默认配置在:default.jfc(https://github.com/openjdk/jdk/blob/master/src/jdk.jfr/share/conf/jfr/default.jfc):

<event&nbsp;name="jdk.ExecutionSample">
&nbsp;&nbsp;&nbsp;&nbsp;<setting&nbsp;name="enabled"&nbsp;control="method-sampling-enabled">true</setting>
&nbsp;&nbsp;&nbsp;&nbsp;<setting&nbsp;name="period"&nbsp;control="method-sampling-java-interval">20 ms</setting>
</event>

<event&nbsp;name="jdk.NativeMethodSample">
&nbsp;&nbsp;&nbsp;&nbsp;<setting&nbsp;name="enabled"&nbsp;control="method-sampling-enabled">true</setting>
&nbsp;&nbsp;&nbsp;&nbsp;<setting&nbsp;name="period"&nbsp;control="method-sampling-native-interval">20 ms</setting>
</event>

默认都是启用的,都是 20ms 一次。这个听上去消耗很大,实际上消耗很小的,详见下一节原理。

采样的原理是?

一切从源码出发https://github.com/openjdk/jdk/blob/master/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp:

//固定开启一个线程,用于 jfr java 方法与原生方法采样
void&nbsp;JfrThreadSampler::run()&nbsp;{
&nbsp;&nbsp;assert(_sampler_thread ==&nbsp;nullptr,&nbsp;"invariant");

&nbsp;&nbsp;_sampler_thread =&nbsp;this;
&nbsp;&nbsp;//获取上次 java 方法采样时间与原生方法采样时间
&nbsp;&nbsp;int64_t&nbsp;last_java_ms =&nbsp;get_monotonic_ms();
&nbsp;&nbsp;int64_t&nbsp;last_native_ms = last_java_ms;
&nbsp;&nbsp;//然后,在一个死循环中,不断的等待采样间隔到达,然后对应采样
&nbsp;&nbsp;while&nbsp;(true) {
&nbsp;&nbsp;&nbsp;&nbsp;//省略等待采样间隔(就是上面的 20ms 配置)的代码
&nbsp;&nbsp;&nbsp;&nbsp;//采样 java 方法
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(next_j <= sleep_to_next) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;task_stacktrace(JAVA_SAMPLE, &_last_thread_java);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;last_java_ms =&nbsp;get_monotonic_ms();
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;//采样原生方法
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(next_n <= sleep_to_next) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;task_stacktrace(NATIVE_SAMPLE, &_last_thread_native);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;last_native_ms =&nbsp;get_monotonic_ms();
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}
}

采样原生方法和 java 方法的代码是一样的,都是调用&nbsp;task_stacktrace&nbsp;方法,这个方法的实现:

static&nbsp;const&nbsp;uint MAX_NR_OF_JAVA_SAMPLES =&nbsp;5;
static&nbsp;const&nbsp;uint MAX_NR_OF_NATIVE_SAMPLES =&nbsp;1;

void&nbsp;JfrThreadSampler::task_stacktrace(JfrSampleType type, JavaThread** last_thread)&nbsp;{
&nbsp;&nbsp;ResourceMark rm;
&nbsp;&nbsp;//对于 java 方法采样,会采样 MAX_NR_OF_JAVA_SAMPLES 即 5 个线程的 java 方法
&nbsp;&nbsp;EventExecutionSample samples[MAX_NR_OF_JAVA_SAMPLES];
&nbsp;&nbsp;//对于原生方法采样,会采样 MAX_NR_OF_NATIVE_SAMPLES 即 1 个线程的原生方法
&nbsp;&nbsp;EventNativeMethodSample samples_native[MAX_NR_OF_NATIVE_SAMPLES];
&nbsp;&nbsp;JfrThreadSampleClosure&nbsp;sample_task(samples, samples_native);

&nbsp;&nbsp;const&nbsp;uint sample_limit = JAVA_SAMPLE == type ? MAX_NR_OF_JAVA_SAMPLES : MAX_NR_OF_NATIVE_SAMPLES;
&nbsp;&nbsp;uint num_samples =&nbsp;0;
&nbsp;&nbsp;JavaThread* start =&nbsp;nullptr;
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;elapsedTimer sample_time;
&nbsp;&nbsp;&nbsp;&nbsp;sample_time.start();
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//获取所有线程列表
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MutexLocker&nbsp;tlock(Threads_lock);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadsListHandle tlh;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JavaThread* current = _cur_index !=&nbsp;-1&nbsp;? *last_thread :&nbsp;nullptr;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;JfrBuffer* enqueue_buffer =&nbsp;get_enqueue_buffer();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(enqueue_buffer !=&nbsp;nullptr,&nbsp;"invariant");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//然后,遍历线程,收集采样数据,直到达到前面提到的 MAX_NR_OF_JAVA_SAMPLES 或 MAX_NR_OF_NATIVE_SAMPLES
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(num_samples < sample_limit) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;current =&nbsp;next_thread(tlh.list(), start, current);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(current ==&nbsp;nullptr) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(start ==&nbsp;nullptr) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;start = current;&nbsp;&nbsp;// remember the thread where we started to attempt sampling
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(current->is_Compiler_thread()) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(enqueue_buffer->free_size() >= _min_size,&nbsp;"invariant");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//判断线程状态是否是符合采样的,并采样
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(sample_task.do_sample_thread(current, _frames, _max_frames, type)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num_samples++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enqueue_buffer =&nbsp;renew_if_full(enqueue_buffer);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*last_thread = current;&nbsp;&nbsp;// remember the thread we last attempted to sample
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;sample_time.stop();
&nbsp;&nbsp;&nbsp;&nbsp;log_trace(jfr)("JFR thread sampling done in %3.7f secs with %d java %d native samples",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sample_time.seconds(), sample_task.java_entries(), sample_task.native_entries());
&nbsp;&nbsp;}
&nbsp;&nbsp;if&nbsp;(num_samples >&nbsp;0) {
&nbsp;&nbsp;&nbsp;&nbsp;sample_task.commit_events(type);
&nbsp;&nbsp;}
}

如何判断线程是否符合采样并采样的呢?这个是在&nbsp;sample_task.do_sample_thread&nbsp;方法中判断的,这个方法的实现:

bool&nbsp;JfrThreadSampleClosure::do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type)&nbsp;{
&nbsp;&nbsp;assert(Threads_lock->owned_by_self(),&nbsp;"Holding the thread table lock.");
&nbsp;&nbsp;//判断线程是否是被排除的,一般 VM 线程是被排除的
&nbsp;&nbsp;if&nbsp;(is_excluded(thread)) {
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;
&nbsp;&nbsp;}

&nbsp;&nbsp;bool&nbsp;ret =&nbsp;false;
&nbsp;&nbsp;//设置线程的 trace flag
&nbsp;&nbsp;thread->set_trace_flag();&nbsp;&nbsp;
&nbsp;&nbsp;//保证线程 trace flag 可见性,仅针对 UseSystemMemoryBarrier 为 true 的情况,默认是 false
&nbsp;&nbsp;if&nbsp;(UseSystemMemoryBarrier) {
&nbsp;&nbsp;&nbsp;&nbsp;SystemMemoryBarrier::emit();
&nbsp;&nbsp;}
&nbsp;&nbsp;
&nbsp;&nbsp;if&nbsp;(JAVA_SAMPLE == type) {
&nbsp;&nbsp;&nbsp;&nbsp;//判断线程是否是处于 RUNNABLE 或者 RUNNING 并且是在运行 java 代码的状态
&nbsp;&nbsp;&nbsp;&nbsp;//如果是,则采样
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(thread_state_in_java(thread)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret =&nbsp;sample_thread_in_java(thread, frames, max_frames);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}&nbsp;else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;assert(NATIVE_SAMPLE == type,&nbsp;"invariant");
&nbsp;&nbsp;&nbsp;&nbsp;//判断线程是否是处于 RUNNABLE 或者 RUNNING 并且是在运行原生代码的状态
&nbsp;&nbsp;&nbsp;&nbsp;//如果是,则采样
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(thread_state_in_native(thread)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret =&nbsp;sample_thread_in_native(thread, frames, max_frames);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;}
&nbsp;&nbsp;clear_transition_block(thread);
&nbsp;&nbsp;return&nbsp;ret;
}

总结看来,JFR 采样的原理就是:

  1. 一个固定的线程,不断的等待采样间隔到达,然后对应采样
  2. 采样的时候,遍历所有线程,判断线程是否符合采样条件,符合则采样
  3. 采样的时候,对于 java 方法采样,会采样最多 5 个线程的 java 方法,对于原生方法采样,会采样最多 1 个线程的原生方法
  4. 采样的时候,判断线程是否符合采样条件,主要是判断线程是否是处于 RUNNABLE 或者 RUNNING 并且是在运行 java 代码或者原生代码的状态

与 async-profiler 的应用场景对比

这两个 JFR 时间一般用于构建 JFR 火焰图,我之前定位代码高 CPU 消耗瓶颈很多是通过这个定位,有一个例子是:https://juejin.cn/post/7325623087209742374

其中这个火焰图:

40296ff516636603ad761cdd4d785723.jpeg

就是 JFR 的&nbsp;jdk.ExecutionSample&nbsp;和&nbsp;jdk.NativeMethodSample&nbsp;事件结合了&nbsp;jdk.ContainerCPUUsage&nbsp;和&nbsp;jdk.ThreadCPULoad&nbsp;事件构建的火焰图。

async profiler 的采样方式,和 JFR 的不同。JFR 的是尽量保持低消耗,但是对于 Java 方法一次采样对于运行 Java 代码的最多 5 个线程,对于 Native 的最多 1 个,但是全局基本不加锁,也不加安全点导致全局暂停,所以消耗很低,并且一般足以定位高 CPU 消耗瓶颈问题(参考上面我发的定位一个实际问题的链接)。async profiler 的采样方式,对于原生方法更详细,对于 Java 方法一般需要 JVM 启动的时候打开&nbsp;-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints,否则只能采集到 Java 安全点时候的方法。因为默认 JVM 为了提高性能,只在安全点的时候添加 Debug 信息用于定位问题带上方法调用信息,加上前面的&nbsp;-XX:+DebugNonSafepoints&nbsp;会去掉限制,在所有位置加上 Debug 信息以及日志记录,这样 async profiler 才能采集到详细的 Java 方法调用信息。所以整体上 async profiler 的采样方式更详细,但是消耗也更大。

建议是,长期开着 JFR,遇到问题优先回溯 JFR,如果 JFR 无法定位问题,再使用 async profiler。

个人简介:个人业余研究了 AI LLM 微调与 RAG,目前成果是微调了三个模型:

  1. 一个模型是基于 whisper 模型的微调,使用我原来做的精翻的视频按照语句段落切分的片段,并尝试按照方言类别,以及技术类别分别尝试微调的成果。用于视频字幕识别。
  2. 一个模型是基于 Mistral Large 的模型的微调,识别提取视频课件的片段,辅以实际的课件文字进行识别微调。用于识别课件的片段。
  3. 最后一个模型是基于 Claude 3 的模型微调,使用我之前制作的翻译字幕,与 AWS、Go 社区、CNCF 生态里面的官方英文文档以及中文文档作为语料,按照内容段交叉拆分,进行微调,用于字幕翻译。

目前,准确率已经非常高了。大家如果有想要我制作的视频,欢迎关注留言。

本人也是开源代码爱好者,贡献过很多项目的源码(Mycat 和 Java JFRUnit 的核心贡献者,贡献过 OpenJDK,Spring,Spring Cloud,Apache Bookkeeper,Apache RocketMQ,Ribbon,Lettuce、 SocketIO、Longchain4j 等项目 ),同时也是深度技术迷,编写过很多硬核的原理分析系列(JVM)。本人也有一个 Java 技术交流群,感兴趣的欢迎关注。

另外,一如即往的是,全网的所有收益,都会捐赠给希望工程,坚持靠爱与兴趣发电。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/538551.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[SystemVerilog]Simulation and Test Benches

Simulation and Test Benches 测试语言中有很大一部分专门用于测试台和测试。在本章中&#xff0c;我们将介绍为硬件设计编写高效测试台的一些常用技术。 6.1 How SystemVerilog Simulator Works 在深入研究如何编写适当的测试台之前&#xff0c;我们需要深入了解模拟器的工作原…

git查看单独某一个文件的历史修改记录

git查看单独某一个文件的历史修改记录 git log -p 文件具体路径 注意&#xff0c;Windows下默认文件路径分隔符是 \&#xff0c;在git bash 里面需要改成 /。 git基于change代码修改与提交_git change-CSDN博客文章浏览阅读361次。git cherry-pick&#xff1a;复制多个提交comm…

使用 Citavi 和 NVivo 简化您的文献综述和研究分析

NVivo 是一款支持定性研究方法和混合研究方法的软件。它可以帮助您收集、整理和分析访谈、焦点小组讨论、问卷调查、音频等内容。NVivo&#xff08;1.0版&#xff09;是Windows和Mac的主要版本。遵循最新的主要版本NVivo 12&#xff08;Windows和Mac&#xff09;。 NVivo 强大…

Java Reflection(从浅入深理解反射)

本节的代码链接&#xff1a;reflection 1. 反射的由来 反射机制允许程序执行期借助于Reflection API取得任何类的内部信息&#xff0c;如成员变量、构造器、成员方法等&#xff0c;并能操作对象的属性及方法&#xff0c;在设计模式和框架底层都会用到。 1.1 引入需求 编写框…

Scala实战:打印九九表

本次实战的目标是使用不同的方法实现打印九九表的功能。我们将通过四种不同的方法来实现这个目标&#xff0c;并在day02子包中创建相应的对象。 方法一&#xff1a;双重循环 我们将使用双重循环来实现九九表的打印。在NineNineTable01对象中&#xff0c;我们使用两个嵌套的fo…

sql注入之宽字节注入

1.1 宽字节注入原理 宽字节注入&#xff0c;在 SQL 进行防注入的时候&#xff0c;一般会开启 gpc&#xff0c;过滤特殊字符。 一般情况下开启 gpc 是可以防御很多字符串型的注入&#xff0c;但是如果数据库编码不 对&#xff0c;也可以导致 SQL 防注入绕过&#xff0c;达到注入…

7、Qt--QLabel使用小记

前言&#xff1a;QLabel作为QT中基础的控件&#xff0c;功能简单使用方便频繁&#xff0c;主要用于显示文本、图片等信息。笔者这里记录下一些开发使用心路&#xff0c;方便小白快速入手。 一、添加背景图片 首先需要在资源中添加好图片资源&#xff0c;图片资源的添加参考4.1…

ArcGIS Desktop使用入门(三)图层右键工具——组织要素模板

系列文章目录 ArcGIS Desktop使用入门&#xff08;一&#xff09;软件初认识 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——标准工具 ArcGIS Desktop使用入门&#xff08;二&#xff09;常用工具条——编辑器 ArcGIS Desktop使用入门&#xff08;二&#x…

每日一练(力扣)

我的思路是暴力枚举: 情况1:相同&#xff0c;就让子串和原串同时后移继续比较 情况2:不相同&#xff0c;就只让原串后移 public int strStr(String haystack, String needle) {if (haystack.length() < needle.length()){return -1;}for (int i 0; i < h…

PointNet++函数square_distance(src, dst):计算两组点之间的欧式距离(代码详解)

文章目录 一、计算两组点之间的欧式距离二、举例三、中间结果输出 一、计算两组点之间的欧式距离 def square_distance(src, dst):"""Calculate Euclid distance between each two points.src^T * dst xn * xm yn * ym zn * zm&#xff1b;sum(src^2, dim-1…

Qt | 对象树与生命期(对象的创建、销毁、擦查找)

一、组合模式与对象树 1、组合模式指的是把类的对象组织成树形结构,这种树形结构也称为对象树,Qt 使用对象树来管理 QObject 及其子类的对象。注意:这里是指的类的对象而不是类。把类组织成树形结构只需使用简单的继承机制便可实现。 2、使用组合模式的主要作用是可以通过…

库、框架、脚手架和IDE一文讲明白

在区分上面几个问题前&#xff0c;咱们先看看几个疑问。 一、常见问题汇总 js css直接复制到服务器 然后引用不就行了么&#xff1f; 为什么还需要安装&#xff1f; 引入js不就是引入了框架了吗&#xff1f;框架就是js&#xff1f; 脚手架和框架都有架&#xff0c;是不是一…

Python | 月平均气候态 | SST

数据来源&#xff1a; NOAA Optimum Interpolation (OI) SST V2 下载地址&#xff1a; https://psl.noaa.gov/data/gridded/data.noaa.oisst.v2.html 空间分辨率: 5.0 degree latitude by 5.0 degree longitude global grid (72x36)87.5N,覆盖范围 01/1856 to 2023/0187.5…

每日一题 — 水果成篮

思路&#xff1a; 通过阅读上面文字得出问题&#xff1a;就去只有两个种类的最大长度的连续子数组&#xff0c;这时我们可以想到用哈希表来存储数据&#xff0c;记录数据的种类和每个种类的数量。 解法一&#xff1a;暴力递归&#xff08;right每次遍历完都回退&#xff09; 解…

十五届web模拟题整理

模拟赛一期 1.动态的Tab栏 请在 style.css 文件中补全代码。 当用户向下滚动的高度没有超过标题栏&#xff08;即 .heading 元素&#xff09;的高度时&#xff0c;保持 Tab 栏在其原有的位置。当滚动高度超过标题栏的高度时&#xff0c;固定显示 Tab 栏在网页顶部。 /* TODO…

01_QT编译报错:Cannot find file:问题解决

QT编译报错&#xff1a;Cannot find file:问题解决 报错原因&#xff1a;创建路径存在中文字符&#xff0c;将文件路径改为英文字符即可

异地两分部子网重复,如何远程更改其中一个分部子网信息

环境: 分部1:子网192.168.1.0/24 分部2:子网192.168.1.0/24 问题描述: 异地两分部子网重复,如何远程更改其中一个分部子网,原本没有问题目前要与总部建ipsec提示冲突无法都建立隧道 解决方案: 先G一下,看看有啥建议 在两个异地分部网络中,如果发现有子网地址出现…

电脑文件名乱码,数据恢复有高招!

在日常使用电脑的过程中&#xff0c;突然遭遇文件名乱码的情况&#xff0c;确实让人头疼不已。原本井井有条的文件目录&#xff0c;一下子变得杂乱无章&#xff0c;文件名变成了一堆无意义的乱码字符。这种情况不仅影响了文件的正常使用&#xff0c;还可能导致重要数据的丢失。…

【C++】拆分详解 - 内存管理

文章目录 前言一、C/C内存分布二、C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free三、C内存管理方式  3.1 new/delete操作内置类型  3.2 new和delete操作自定义类型  3.3 operator new与operator delete函数 四、new和delete的实现原理  4.1 内置类型…

智能助力:大模型自动填写工单准确率达95%

基于大模型优秀的问答、总结和话术生成能力&#xff0c;主流联络中心纷纷接入大模型升级智能知识库、智能工单、智能陪练等应用。 以智能填单为例&#xff0c;借助大模型能够轻松从对话中提取出实体信息、判定对话意图、识别情绪、生成沟通摘要等。通过简单的Prompt&#xff0c…