本文共 3989 字,大约阅读时间需要 13 分钟。
在 Java 16 中,JDK 引入了一个新的事件 ObjectAllocationSample,用于监控对象分配过程中的关键问题。这个事件的主要目的是帮助开发者识别在高负载环境下可能导致性能瓶颈的对象分配行为。
在大多数 Java 应用中,对象的分配主要发生在 TLAB(Thread-Local Allocation Buffer)中。如果 TLAB 外分配或重分配过多,可能会导致内存管理问题。为了更好地监控这些问题,JDK 提供了两个事件:ObjectAllocationOutsideTLAB 和 ObjectAllocationInNewTLAB。然而,这些事件默认会记录堆栈信息,这在高负载情况下会显著增加性能开销。为了解决这一问题,ObjectAllocationSample 事件被引入,通过采样机制来减少对堆栈信息的采集,从而平衡监控与性能之间的关系。
| 属性 | 值 | 描述 |
|---|---|---|
| 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); } }} ObjectAllocationSample 事件的采样机制weight 属性。objectClass 属性表示分配的对象类型,weight 属性表示线程分配的对象总大小。转载地址:http://yjgbz.baihongyu.com/