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

本文共 3989 字,大约阅读时间需要 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/

    你可能感兴趣的文章
    Nacos安装教程(非常详细)从零基础入门到精通,看完这一篇就够了
    查看>>
    Nacos配置中心集群原理及源码分析
    查看>>
    nacos配置自动刷新源码解析
    查看>>
    Nacos集群搭建
    查看>>
    nacos集群搭建
    查看>>
    Navicat for MySQL 查看BLOB字段内容
    查看>>
    Neo4j电影关系图Cypher
    查看>>
    Neo4j的安装与使用
    查看>>
    Neo4j(2):环境搭建
    查看>>
    Neo私链
    查看>>
    nessus快速安装使用指南(非常详细)零基础入门到精通,收藏这一篇就够了
    查看>>
    Nessus漏洞扫描教程之配置Nessus
    查看>>
    Nest.js 6.0.0 正式版发布,基于 TypeScript 的 Node.js 框架
    查看>>
    NetApp凭借领先的混合云数据与服务把握数字化转型机遇
    查看>>
    NetBeans IDE8.0需要JDK1.7及以上版本
    查看>>
    netcat的端口转发功能的实现
    查看>>
    netfilter应用场景
    查看>>
    netlink2.6.32内核实现源码
    查看>>
    Netpas:不一样的SD-WAN+ 保障网络通讯品质
    查看>>
    NetScaler的常用配置
    查看>>