add
This commit is contained in:
+204
@@ -0,0 +1,204 @@
|
||||
### 写在前面
|
||||
|
||||
- 文章出处:https://zhuanlan.zhihu.com/c_1264859821121355776
|
||||
- 关注大佬:https://www.zhihu.com/people/zhxhash
|
||||
|
||||
我只是对大佬的专栏文章内容做一个笔记,加深记忆和理解。
|
||||
|
||||
### 什么是JFR?
|
||||
JFR是**Java Flight Record**(Java飞行记录)的缩写,是JVM内置的基于事件的监控记录框架。这个起名参考了黑匣子对于飞机的作用,将Java进程比喻成飞机飞行。顾名思义,JFR主要用于问题定位和持续监控。
|
||||
|
||||
### JFR版本
|
||||
**JFR 0.9**版本对应**JDK7和8**,在8u40之后,可以在运行时开启/关闭。**JFR 1.0**版本对应**JDK9和10**,在这一版本之后,增加了JFR事件接口,用户可以生产或者消费某种事件。**JFR 2.0**版本对应**JDK11**,下面的参数都是基于这一版本。
|
||||
|
||||
### 为什么用JFR?
|
||||
为了在生产环境更好的定位问题。JDK提供了一个可以长期开启,对应用影响很小的持续监控手段,官方的目标是开启JFR监控(默认配置,非profile)**对性能的影响在1%以内,对JVM Runtime、GC、OS以及Java库进行全方位的监控。**
|
||||
|
||||
### JFR的核心(Event)
|
||||
在JFR中一切皆为Event,任意JVM行为都是一个Event,例如:
|
||||
|
||||
- 类加载,Class Load Event
|
||||
- 开启JFR记录,Recording Reason Event
|
||||
- 就算是 Event 丢失,也是一个 Data Loss Event
|
||||
|
||||
Event 在某些特定的时间点产生,**由名称、时间戳、Event 数据体组成。**不同的 Event 数据体不同(例如 CPU 负载,Event 前后的 Java 堆大小,获取锁的线程 ID 等)
|
||||
|
||||
大部分的 Event,都有 Event 是在哪个线程发生的、线程的调用栈、Event 持续时间,利用这些信息,我们可以回溯 Event 发生当时的情况。
|
||||
|
||||
### Event类型
|
||||
Event 按照采集方式可以分为三种:
|
||||
|
||||
- Instant Event,这种 Event 在发生时就立刻采集。例如:Throw Exception Event、Thread Start Event,这种在某一时刻发生的 Event
|
||||
- Duration Event,这种 Event 在完成的时候记录。因为需要耗费一些时间,但可以设置一个时间限制,超时才记录。例如:GC Event、Thread Sleep Event
|
||||
- Sample Event(Requestable Event)这种 Event 按照一定的频率采集。频率是可以配置的,例如:Thread Dump Event、Method Sampling Event
|
||||
|
||||
由于 JFR 会采集很多很多的数据,为了效率,最好配置自己感兴趣的事件采集。并且对于 Duration Event 设置时间限制,一般我们对于时间短的事件并不关心。
|
||||
|
||||
|
||||
### Event存储
|
||||
Event 会被写入`.jfr`的二进制文件中,以`little endian base 128`的形式编码,以 Class Load Event 举个例子:
|
||||
|
||||
```
|
||||
0000FC10 : 98 80 80 00 87 02 95 ae e4 b2 92 03 a2 f7 ae 9a 94 02 02 01 8d 11 00 00
|
||||
```
|
||||
|
||||
- 0000FC10: 文件位置
|
||||
- 98 80 80 00: Event大小
|
||||
- 87 02: Event ID
|
||||
- 95 ae e4 b2 92 03: 时间戳
|
||||
- a2 f7 ae 9a 94 02: 持续时间
|
||||
- 02: 线程 ID
|
||||
- 01: 堆栈 ID
|
||||
- 8d 11: 加载的类
|
||||
- 00 : 定义类的 ClassLoader
|
||||
- 00 : 初始化类的 ClassLoader
|
||||
|
||||
> 实际使用中,通过可视化工具**JMC**查看`.jfr`文件
|
||||
|
||||
### 如何实现的低延迟、低性能损耗?
|
||||
|
||||
Event 是多线程产生的,如果 Event 记录要保证全局有序,那么肯定需要多线程向一个指定队列或者缓存输出,那么不可避免的会涉及到锁争用,这样是很低效的。而 Event 本身带时间戳,所以记录时不需要排序,将每个线程内的记录,合并成一个集合后再进行排序高效得多。
|
||||
|
||||
<img width='70%' src='https://pic3.zhimg.com/v2-5530b8a77d0d45ac12dd879ccf7afce8_1440w.jpg'/>
|
||||
|
||||
1. 所有的 Event 会先存储到每个线程自己的 Thread Buffer(默认8KB,这是一个经验值)
|
||||
2. Thread Buffer 满了之后刷入 Global Buffer(可配置)
|
||||
3. Global Buffer 满了之后会选择丢弃或者刷入文件(可配置)
|
||||
|
||||
*Thread Buffer 中的数据要么在内存中,要么就在磁盘里。不会两个地方都存在。*
|
||||
|
||||
#### JFR记录数据丢失?
|
||||
|
||||
- 断电、操作系统强制重启
|
||||
- kill -9 了 Java 进程
|
||||
- JVM 崩溃
|
||||
|
||||
以上三种情况,刷入文件的 Event 不会丢,但内存里的 Global Buffer、Thread Buffer 会丢。对于JVM正常退出(含应用异常但JVM正常退出)的情况,数据不会丢。
|
||||
|
||||
⚠️数据在从 Thread Buffer 刷入 Global Bufeer 的时候, 去 dump JFR 的数据,可能这部分数据会被忽略而导致看不到。
|
||||
|
||||
⚠️从 Global Buffer 刷入磁盘不够快的时候,这时候要刷入磁盘的数据可能被丢弃。此时会记录下 Data Loss Event 包含了哪块时间的数据丢了,通过 JFR 日志也能看到这个信息。
|
||||
|
||||
### 开启JFR
|
||||
有2种方式开启,通过启动参数在启动的时候开启、jcmd在运行时启用/关闭。
|
||||
|
||||
#### 启动参数
|
||||
|
||||
在JDK11以后,启动参数简化了。
|
||||
|
||||
- 启动JFR记录的参数:`-XX:StartFlightRecording`
|
||||
- 用于配置JFR的参数:`-XX:FlightRecorderOptions`
|
||||
|
||||
*JDK8中的`-XX:+FlightRecorder`状态位不再需要了*
|
||||
|
||||
#### StartFlightRecording
|
||||
|
||||
|配置项|默认|说明|
|
||||
|:-----|:-----|:-----|
|
||||
|delay|0|延迟多久后启动 JFR 记录,支持带单位,例如:delay=60s、delay=20m、delay=1h、 delay=1d|
|
||||
|disk |true|是否写入磁盘,控制 global buffer 满了之后,是丢弃还是写入磁盘|
|
||||
|dumponexit |false |程序退出时,是否要dump出 .jfr文件|
|
||||
|duration | 0 | JFR 记录持续时间,支持单位配置,0代表一直记录|
|
||||
|filename |- | dump的输出文件,例如:启动目录/hotspot-pid-26732-id-1-2020_03_12_10_07_22.jfr,pid是进程id,id后面的1代表第1个jfr文件|
|
||||
|name | - | 由于可以启动多个 JFR 记录,这个名称用于区分,否则只能看到一个记录 id,不好区分|
|
||||
|maxage | 0 | disk=true生效,global buffer 刷入的文件保留时间,支持单位配置,0代表一直保存|
|
||||
|maxsize | - | disk=true生效,global buffer 刷入的文件最大值,支持单位配置(MB、GB)例如:250MB,这个配置不能小于**maxchunksize**参数|
|
||||
|path-to-gc-roots| false | 是否记录GC根节点到活动对象的路径,一般不打开这个,性能损耗比较大,会导致FullGC。一般是在怀疑有内存泄漏、通过对象堆栈无法定位的时候动态打开。例如 ThreadLocal 没有释放这样的,可以在 dump 的时候采集 gc roots|
|
||||
|settings | default.jfc| 采集 Event 的详细配置,可选值:default.jfc、profile.jfc|
|
||||
|
||||
#### FlightRecorderOptions
|
||||
|
||||
|配置项|默认|说明|
|
||||
|:-----|:-----|:-----|
|
||||
|allow_threadbuffers_to_disk | false | 在 thread buffer 线程阻塞的时候,是否将 thread buffer 内容直接写入文件。一般没必要开启这个参数,只要设置的参数让 global buffer 大小合理不至于刷盘很慢就行了|
|
||||
|globalbuffersize |-|单个 global buffer 的大小,一般通过 memorysize 设置,自动计算得出,不建议自己设置|
|
||||
|numglobalbuffers |-| global buffer 的个数,一般通过 memorysize 设置,自动计算得出,不建议自己设置|
|
||||
|maxchunksize | 12MB | 存入磁盘的每个临时文件的大小,不能小于1MB,不能比**memorysize**小,更不能比**globalbuffersize**小,会导致性能下降|
|
||||
|memorysize | 10MB | global buffer 占用的整体内存大小 |
|
||||
|old-object-queue-size | 256 | 针对**Profiling**中的**Old Object Sample 事件**收集多少个**Old Object**。大佬的建议是256够用,时间跨度大的,例如 maxage 保存了一周以上的,可以翻倍|
|
||||
|repository |-| 保存到磁盘的位置,等同于 -Djava.io.tmpdir 指定的目录|
|
||||
|retransform | true | 是否通过 JVMTI 转换 JFR 相关 Event 类,如果设置为 false,则只在 Event 类加载的时候添加相应的 Java Instrumentation。一般不用改,这点内存 metaspace 还是足够的|
|
||||
|samplethreads | true | 是否开启线程采集的状态位配置,只有为 true,且在 Event 配置中开启了线程相关的采集,才会采集这些事件,后面会展开说|
|
||||
|stackdepth | 64 | 采集事件堆栈深度,有些 Event 会采集堆栈,这个堆栈采集的深度,统一由这个配置指定。这个值不能设置过大,堆栈深度过大会影响性能。比如你用的是 default.jfc 配置的采集,堆栈深度64基本上就是不影响性能的极限了。可以自定义采集某些事件,增加堆栈深度。|
|
||||
|threadbuffersize | 8KB | Thread Buffer 大小,增加会带来更多内存开销,减小会增加刷入 global buffer 的次数,8KB 是一个经验值|
|
||||
|
||||
#### disk=true
|
||||
|
||||
当 global buffer 满了,写入 repository 配置的目录,这个临时目录是**对用户不可见的**,临时目录地址是-Djava.io.tmpdir指定的,默认为:
|
||||
|
||||
- linux: /tmp
|
||||
- windows: C:\Users\用户名\AppData\Temp
|
||||
|
||||
目录结构的命名格式:时间_pid,例如:
|
||||
|
||||
```
|
||||
--/2020_03_12_08_04_45_10916
|
||||
|----2020_03_12_08_04_45.jfr
|
||||
|----2020_03_12_08_05_12.jfr
|
||||
|----2020_03_12_08_05_55.jfr
|
||||
|----2020_03_12_08_06_08.jfr
|
||||
|----2020_03_12_08_06_08.part
|
||||
```
|
||||
每个.jfr就是一个 Data trunk,最新的文件就是`.part`,每个jfr文件的大小=Data trunk的大小。
|
||||
|
||||
#### dumponexit=true
|
||||
|
||||
程序退出的时候,强制dump一次将数据输出到 filename 配置的文件。用户手动dump也会存储到这个文件,**输出到这个文件目录的.jfr文件才对用户可见。**
|
||||
|
||||
输出这个文件是不慢的,就是把内存里的buffer以及临时目录中的.jfr文件合并后输出。⚠️注意不能把内存里的buffer配的过大,否则可能会导致内存不足,引发FullGC。
|
||||
|
||||
### JFR的内存占用?
|
||||
|
||||
- thread buffer:线程数量 * thread buffer 大小(默认8kb)
|
||||
- global buffer:总大小由【memorysize】自动计算得出
|
||||
|
||||
相加就是JFR的总内存占用。
|
||||
|
||||
|
||||
### 运行时通过jcmd开启/关闭
|
||||
|
||||
#### 开启JFR记录
|
||||
eg:`jcmd <pid> JFR.start name=profile_online maxage=1d maxsize=1g`,JFR.start 后面的参数和*-XX:StartFlightRecording*一样
|
||||
|
||||
#### 停止JFR记录
|
||||
eg:`jcmd <pid> JFR.stop name=profile_online`
|
||||
|
||||
#### 查看当前正在执行的 JFR 记录
|
||||
eg:`jcmd <pid> JFR.check`
|
||||
|
||||
输出eg:
|
||||
|
||||
```
|
||||
<pid>:
|
||||
Recording 1: 参数列表 (running)
|
||||
```
|
||||
#### 查看配置
|
||||
`jcmd <pid> JFR.configure`,不传入参数,则是查看当前配置。传入参数就是修改配置,与*-XX:FlightRecorderOptions*一样。
|
||||
|
||||
输出eg:
|
||||
|
||||
```
|
||||
Repository path: /tmp/2020_03_18_08_41_44_21
|
||||
|
||||
Stack depth: 64
|
||||
Global buffer count: 20
|
||||
Global buffer size: 512.0 kB
|
||||
Thread buffer size: 8.0 kB
|
||||
Memory size: 10.0 MB
|
||||
Max chunk size: 12.0 MB
|
||||
Sample threads: true
|
||||
```
|
||||
#### 输出dump文件
|
||||
`jcmd <pid> JFR.dump`
|
||||
|
||||
|参数 | 默认 | 描述|
|
||||
|:-----|:-----|:-----|
|
||||
|name | - | 指定要查看的 JFR 记录名称|
|
||||
|filename | 无 | 指定输出位置|
|
||||
|maxage | 0 | dump的时间范围的文件,配置和上文介绍的一样|
|
||||
|maxsize | 0 | dump最大文件大小,配置和上文介绍的一样|
|
||||
|begin | - | dump开始位置, 可以这么配置:09:00, 21:35:00, 2018-06-03T18:12:56.827Z, 2018-06-03T20:13:46.832, -10m, -3h, -1d|
|
||||
|end |-| dump结束位置,可以这么配置: 09:00, 21:35:00, 2018-06-03T18:12:56.827Z, 2018-06-03T20:13:46.832, -10m, -3h, -1d|
|
||||
|path-to-gc-roots| false | 一般不开启,dump 的时候打开这个肯定会触发一次 fullGC,对线上应用有影响|
|
||||
|
||||
<a href='./1_查看JFR事件的工具JMC.md' target='_blank'>查看下一节</a>
|
||||
@@ -0,0 +1,30 @@
|
||||
### Java Mission Control
|
||||
|
||||
- 官网下载地址:https://adoptium.net/zh-CN/jmc/
|
||||
- 大佬提供的下载地址:https://zhxhash-blog.oss-cn-beijing.aliyuncs.com/resources/jmc.zip
|
||||
|
||||
解压后执行 jmc.exe 无法启动的话,可能是没有配置JDK环境变量或JDK版本低于 JDK 11 导致的。可以配置JDK环境变量,也可以在 jmc.exe 同级目录下创建一个 jre 目录,将jdk的完整目录结构拷贝至该目录,都可以正常打开 jmc.exe。
|
||||
|
||||
### 使用方式
|
||||
|
||||
先 dump 一份jfr记录文件,<a href='./0_初识Java%20Flight%20Record.md' target='_blank'>上一篇文章</a>有介绍具体的操作方法,建议利用 begin 还有 end 参数截取你感兴趣的时间段,控制一下jfr文件的大小。然后再回到jmc里通过【文件】/【打开文件】/【选择dump的jfr文件】打开。由于jfr文件里的数据要导入内存,然后生成索引和报表,实际内存占用大概是原始文件的4~6倍左右。如果你的系统内存不足,JMC会提示你只截取一部分查看。
|
||||
|
||||
### JVM调优简单示例
|
||||
|
||||
线上某个实例,dump出了 jfr 文件。下载到本地,按照持续时间倒序查看 GC Event:
|
||||
|
||||
<img width='80%' src='https://picx.zhimg.com/v2-85908b178dbd3adc1a420ddc4f43683f_1440w.jpg'>
|
||||
|
||||
有一些耗时比较高的**GC 事件(Old GC)**原因是**G1 Humongous Allocation**。
|
||||
|
||||
在G1中**大于 region 50%**的对象视为大对象,频繁分配大对象会导致性能问题。如果 region 里面包含大量的大型对象,则该 region 中**最后一个具有巨型对象的区域**与**区域末端之间的空间**将不会使用,导致堆内存空间碎片化。调整的方法一般是**修改 region 的大小 > 这类大对象的 2 倍以上**。那么这个大对象有多大呢?我们可以通过*Old Object Sample*来查看老对象采样,一般随着你的程序运行时间增长,这个采集会更加准确地命中到你最关注的对象。
|
||||
|
||||
<img width='80%' src='https://pica.zhimg.com/v2-19dc5e1d4e9fd1f249f736c7aed0e94a_r.jpg'>
|
||||
|
||||
注意 **heap used 是当前所有对象占用的内存大小**。这个对象大小,可以通过数组大小计算而出,这里最大就是 3.31 * 10^6 字节。我们再来看一下当前*G1HeapRegionSize*的配置,通过查看*Unsiged Long Flag Event*
|
||||
|
||||
<img width='80%' src='https://pic3.zhimg.com/v2-be449976acc125243d2b57f1946365cc_r.jpg'>
|
||||
|
||||
发现大小是:4.19 * 10^6 字节,不足最大对象的两倍。所以我们需要将*G1HeapRegionSize*至少调整到 6.62 * 10^6 字节,调整之后,不再出现 G1 Old GC。
|
||||
|
||||
<a href='./0_初识Java%20Flight%20Record.md' target='_blank'>返回上一节</a> <a href='./2_Event结构及配置.md' target='_blank'>查看下一节</a>
|
||||
@@ -0,0 +1,54 @@
|
||||
### Event 结构
|
||||
|
||||
- Event 大小
|
||||
- Event ID
|
||||
- 时间戳
|
||||
- 持续时间
|
||||
- 相关线程 ID
|
||||
- 相关堆栈 ID
|
||||
|
||||
每个 Event 还会有自己的 Payload,承载自己要采集的数据。但不是每个 Event 都填充上面的字段,只是结构里面有,并不会采集。
|
||||
|
||||
### Event采集的公共配置
|
||||
|
||||
- enabled:是否启用这个 Event 的采集,true/false
|
||||
- cutoff:是否截断,例如:1d、1h、1m、1s、1ms、1ns,0=不截断
|
||||
- stackTrace:是否启用堆栈跟踪,true/false
|
||||
- period:采集周期
|
||||
+ beginChunk:在每一个 Data Chunk 写满另起一个的时候,立刻采集一次
|
||||
+ everyChunk:在每一个 Data Chunk 写到占用一半空间限制的时候,立刻采集一次
|
||||
+ endChunk:在每一个 Data Chunk 写满的时候,立刻采集一次
|
||||
+ 或者配置具体时间,例如:1d、1h、1m、1s、1ms、1ns
|
||||
- threshold:Event 持续时间超过这个阈值才会采集,例如:1d、1h、1m、1s、1ms、1ns
|
||||
|
||||
Event采集详细配置,JDK自带两个模板,在 $JAVA_HOME/lib/jfr 目录下,里面配置格式是一个xml文件,取其中一个配置举个例子,例如:
|
||||
|
||||
```xml
|
||||
<event name="jdk.OldObjectSample">
|
||||
<setting name="enabled" control="memory-leak-detection-enabled">true</setting>
|
||||
<setting name="stackTrace" control="memory-leak-detection-stack-trace">false</setting>
|
||||
<setting name="cutoff" control="memory-leak-detection-cutoff">0 ns</setting>
|
||||
</event>
|
||||
```
|
||||
这个就是 OldObject 采集 Event 的配置,这里配置为:
|
||||
|
||||
- 启用这个Event采集
|
||||
- 不采集堆栈
|
||||
- 不截断
|
||||
|
||||
你也可以加上 period 和 threshold 配置,但对这个 Event 没啥效果。**这里有个 control 属性,接下来会提到。**
|
||||
|
||||
### 举一个自定义配置的例子
|
||||
|
||||
我们一般通过 JMC 来配置这些 jfr 文件。打开【窗口】/【飞行记录模板管理器】,将 default.jfc 和 profile.jfc 导入进去。先看 default.jfc,点击【编辑】,弹出一个【快速编辑模板】这里是在整体上让你快速配置,是基于 default.jfc 里面的 selection 标签还有 condition 标签。举个例子:
|
||||
|
||||
<img width='80%' src='https://pic2.zhimg.com/v2-af3a277d056fd6080e4ced13858ab9bb_1440w.jpg'>
|
||||
|
||||
这里配置的*Memory Leak Detection*对应其中*Memory Leak Detection*的*selection*标签,只有:
|
||||
|
||||
- memory-leak-detection = off
|
||||
- memory-leak-detection-enabled = false
|
||||
|
||||
这样 OldObjectSample 的 enabled 才为 false,因为`<setting name="enabled" control="memory-leak-detection-enabled">true</setting>`,点击【高级】会跳转到所有 Event 的具体配置。在接下来的章节,我们来讲一下所有 Event 的采集详细配置。
|
||||
|
||||
<a href='./1_查看JFR事件的工具JMC.md' target='_blank'>返回上一节</a> <a href='./3_Event采集详细配置.md' target='_blank'>查看下一节</a>
|
||||
@@ -0,0 +1,39 @@
|
||||
### JFR 相关 Event
|
||||
|
||||
一共4个 Event,但是需要关心的就下面这两个,在 default.jfc 中默认是启用的。
|
||||
|
||||
- Data Loss:发生数据丢失时记录,包括:
|
||||
+ 开始时间
|
||||
+ Amount:本次丢失多少事件
|
||||
+ Total:一共丢失多少事件
|
||||
- Recording Setting:每次产生新的 Data Chunk 的时候,采集一次所有的 Event 的详细配置,记录到这个 Event 中
|
||||
|
||||
### JAVA 应用相关 Event
|
||||
|
||||
##### 1、Thread Local Allocation Buffer(TLAB)
|
||||
|
||||
TLAB 目的是为了快速分配内存。堆内存是线程共享的,所以在堆内存直接分配对象,就会锁定整个堆,这样效率太低。TLAB 是位于堆内存的一块内存区域,在为每个线程分配 TLAB 的时候才会锁定堆(G1 是 CAS 分配)。这样一来,每个线程在分配对象的时候,优先从 TLAB 上分配。大对象的分配不会发生在 TLAB,将会涉及到线程同步。这是比较笼统的看法,G1 的情况更加复杂。为了能说明 JFR 相关事件的意义,这里继续深入一下关于 G1 TLAB 相关原理。创建一个对象时:
|
||||
|
||||
- 首先尝试从线程现有的TLAB空间分配内存
|
||||
- 如果剩余空间不足,查看是否能分配一个新的TLAB,再分配内存给对象。每个线程的 TLAB 大小是随着线程运行不断变化的。TLAB 的内部,每个线程维护着一个*refill_waste*的变量,这个变量的值,决定是否能分配一个新的TLAB。
|
||||
- 当 TLAB 剩余空间不足时,查看当前 TLAB 的剩余大小
|
||||
+ 如果小于*refill_waste*则需要分配一个新的TLAB,这时候,JFR 会产生一条*ObjectAllocationInNewTLAB*记录
|
||||
+ 否则认为这个 TLAB 还不算满,当前这个对象将直接走堆上内存分配,这时会产生一条*ObjectAllocationOutsideTLAB*记录
|
||||
|
||||
*ObjectAllocationInNewTLAB*在 default.jfc 中默认关闭,可以通过向导配置*memory-profiling*调为*memory-profiling-enabled-medium*打开。也可以用高级配置这个 Event 是否采集,以及堆栈是否采集。采集内容包括:时间、线程、本次需要分配内存大小、对象类型、当前 TLAB 大小。
|
||||
|
||||
*ObjectAllocationOutsideTLAB*在 default.jfc 中也是默认关闭的,可以通过向导配置*memory-profiling*调为*memory-profiling-enabled-medium*打开。也可以用高级配置这个 Event 是否采集,以及堆栈是否采集。采集内容包括:时间、线程、本次需要分配内存大小、对象类型。
|
||||
|
||||
**这两个的采集,对性能影响比较大,不能长期跑。尤其是在启用堆栈收集后,影响就更大了。一般考虑动态打开。**如果需要定位大对象分配代码位置,可以采集一个时间段的*ObjectAllocationOutsideTLAB*查看最大需要的内存大小是多少,通过减少内存分配来减少GC。或者查看造成这些事件的热点堆栈是哪里,然后优化代码。示例打开配置:
|
||||
|
||||
```xml
|
||||
<event name="jdk.ObjectAllocationInNewTLAB">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="stackTrace">true</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ObjectAllocationOutsideTLAB">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="stackTrace">true</setting>
|
||||
</event>
|
||||
```
|
||||
Reference in New Issue
Block a user