博客
关于我
Java JFR 民间指南 - 事件详解 - jdk.ObjectAllocationSample
阅读量:477 次
发布时间:2019-03-06

本文共 3939 字,大约阅读时间需要 13 分钟。

Java 16 中的对象分配采样事件:JDK ObjectAllocationSample

引入

在 Java 16 中,JDK 引入了一个新的事件 ObjectAllocationSample,用于监控对象分配过程中的关键问题。这个事件的主要目的是帮助开发者识别在高负载环境下可能导致性能瓶颈的对象分配行为。


事件背景

在大多数 Java 应用中,对象的分配主要发生在 TLAB(Thread-Local Allocation Buffer)中。如果 TLAB 外分配或重分配过多,可能会导致内存管理问题。为了更好地监控这些问题,JDK 提供了两个事件:ObjectAllocationOutsideTLABObjectAllocationInNewTLAB。然而,这些事件默认会记录堆栈信息,这在高负载情况下会显著增加性能开销。为了解决这一问题,ObjectAllocationSample 事件被引入,通过采样机制来减少对堆栈信息的采集,从而平衡监控与性能之间的关系。


事件配置

Java 16 的默认配置

属性 描述
enabled true 默认启用。
throttle 150/s 每秒最多采集 150 个事件。
stackTrace true 采集事件时同时记录堆栈信息。

采样配置

属性 描述
enabled true 默认启用。
throttle 300/s 每秒最多采集 300 个事件。
stackTrace true 采集事件时同时记录堆栈信息。

事件包含的属性

属性 说明 示例
startTime 事件开始时间(格式化为 HH:mm:ss.fff)。 10:16:24.677
objectClass 触发事件的对象类。 byte[] (classLoader = bootstrap)
weight 该线程距离上次被采集 ObjectAllocationSample 事件的时间内,线程分配的对象总大小。 10.0 MB
eventThread 事件所属线程。 "main"(线程 ID 为 1)。
stackTrace 线程堆栈信息。 com.github.hashjang.jfr.test.TestObjectAllocationSample.main(String[]) line: 42

测试示例

以下是一个使用 ObjectAllocationSample 事件的测试案例。该测试模拟了多线程环境下的对象分配,展示了事件的采集情况:

public class TestObjectAllocationSample {    private static final int BYTE_ARRAY_OVERHEAD = 16;    private static final int OBJECT_SIZE = 1024 * 1024;    private static final int OBJECTS_TO_ALLOCATE = 20;    private static final String BYTE_ARRAY_CLASS_NAME = new byte[0].getClass().getName();    private static final String INT_ARRAY_CLASS_NAME = new int[0].getClass().getName();    private static final String EVENT_NAME = "jdk.ObjectAllocationSample";    public static byte[] tmp;    public static int[] tmp2;    public static void main(String[] args) throws IOException, InterruptedException {        WhiteBox whiteBox = WhiteBox.getWhiteBox();        whiteBox.fullGC();        Recording recording = new Recording();        recording.enable(EVENT_NAME).with("throttle", "1/s");        recording.start();        Runnable runnable = () -> {            for (int i = 0; i < OBJECTS_TO_ALLOCATE; ++i) {                tmp = new byte[OBJECT_SIZE - BYTE_ARRAY_OVERHEAD];                TimeUnit.MILLISECONDS.sleep(100);            }        };        Thread thread = new Thread(runnable);        Thread thread2 = new Thread(() -> {            for (int i = 0; i < OBJECTS_TO_ALLOCATE; ++i) {                tmp2 = new int[OBJECT_SIZE - BYTE_ARRAY_OVERHEAD];                TimeUnit.MILLISECONDS.sleep(100);            }        });        thread.start();        thread2.start();        thread.join();        thread2.join();        recording.stop();        Path path = new File(new File(".").getAbsolutePath(), "recording-" + recording.getId() + "-pid" + ProcessHandle.current().pid() + ".jfr").toPath();        recording.dump(path);        for (RecordedEvent event : RecordingFile.readAllEvents(path)) {            if (!EVENT_NAME.equals(event.getEventType().getName())) {                continue;            }            String objectClassName = event.getString("objectClass.name");            boolean isMyEvent = (Thread.currentThread().getId() == event.getThread().getJavaThreadId() ||                                 thread.getId() == event.getThread().getJavaThreadId() ||                                 thread2.getId() == event.getThread().getJavaThreadId()) &&                               (objectClassName.equals(BYTE_ARRAY_CLASS_NAME) || objectClassName.equals(INT_ARRAY_CLASS_NAME));            if (!isMyEvent) {                continue;            }            System.out.println(event);        }    }}

事件的底层原理

Java 对象分配流程

  • TLAB 分配:如果 TLAB 有足够空间,则在 TLAB 中分配对象。
  • TLAB 重分配:如果 TLAB 满不够空间,但浪费空间未超过阈值,则扩展 TLAB。
  • TLAB 外分配:如果以上条件不满足,则在堆外分配对象。
  • ObjectAllocationSample 事件的采样机制

  • Throttle 配置:通过 EWMA 算法实现动态控制采样频率,确保在高负载情况下不会过度采集。
  • 权重计算:记录线程距离上次采集的时间内分配的对象总大小,作为事件的 weight 属性。
  • 优化采样:对大对象分配采样次数增加,以提高采集准确性。

  • 总结

    • ObjectAllocationSample 是 Java 16 中用于优化对象分配监控的重要事件。
    • 事件的 objectClass 属性表示分配的对象类型,weight 属性表示线程分配的对象总大小。
    • JVM 通过动态调整采样频率(基于 EWMA 算法),保证在高负载环境下依然能够有效监控对象分配问题。
    • 建议在实际应用中根据性能需求调整采样频率,并结合堆栈信息分析,找到分配瓶颈并优化代码。

    转载地址:http://yjgbz.baihongyu.com/

    你可能感兴趣的文章
    Netty的Socket编程详解-搭建服务端与客户端并进行数据传输
    查看>>
    Netty相关
    查看>>
    Netty遇到TCP发送缓冲区满了 写半包操作该如何处理
    查看>>
    Netty:ChannelPipeline和ChannelHandler为什么会鬼混在一起?
    查看>>
    Netty:原理架构解析
    查看>>
    Network Dissection:Quantifying Interpretability of Deep Visual Representations(深层视觉表征的量化解释)
    查看>>
    Network Sniffer and Connection Analyzer
    查看>>
    Network 灰鸽宝典【目录】
    查看>>
    NetworkX系列教程(11)-graph和其他数据格式转换
    查看>>
    Networkx读取军械调查-ITN综合传输网络?/读取GML文件
    查看>>
    network小学习
    查看>>
    Netwox网络工具使用详解
    查看>>
    Net与Flex入门
    查看>>
    net包之IPConn
    查看>>
    Net操作配置文件(Web.config|App.config)通用类
    查看>>
    Neutron系列 : Neutron OVS OpenFlow 流表 和 L2 Population(7)
    查看>>
    New Relic——手机应用app开发达人的福利立即就到啦!
    查看>>
    NFinal学习笔记 02—NFinalBuild
    查看>>
    NFS
    查看>>
    NFS Server及Client配置与挂载详解
    查看>>