<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/how-we-improved-apm-java-startup-by-encoding-a-prefix-trie-as-a-jvm-constant-fogkaahmp" -->

---
title: How we improved APM Java startup by encoding a prefix...
description: Datadog's APM team reduced class-matching overhead by 30% over four years, with a key optimization being ClassNameTrie — a prefix trie encoded as a single JVM...
canonical: https://daily.dev/posts/how-we-improved-apm-java-startup-by-encoding-a-prefix-trie-as-a-jvm-constant-fogkaahmp
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: How we improved APM Java startup by encoding a prefix trie as a JVM constant | daily.dev
og:description: Datadog's APM team reduced class-matching overhead by 30% over four years, with a key optimization being ClassNameTrie — a prefix trie encoded as a single JVM...
og:url: https://daily.dev/posts/how-we-improved-apm-java-startup-by-encoding-a-prefix-trie-as-a-jvm-constant-fogkaahmp
og:image: https://api.daily.dev/og/posts/FoGKAaHmP.png
og:image:alt: How we improved APM Java startup by encoding a prefix trie as a JVM constant
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How we improved APM Java startup by encoding a prefix trie as a JVM constant

**[Datadog](https://daily.dev/sources/datadog)** · 12 min read · 1 upvotes · 0 comments

## Summary

Datadog's APM team reduced class-matching overhead by 30% over four years, with a key optimization being ClassNameTrie — a prefix trie encoded as a single JVM string constant. During JVM startup (premain phase), the JIT compiler is cold or absent, making conventional data structure construction expensive. By encoding the trie as a string constant loaded via a single ldc bytecode instruction, the team avoided I/O, resource lookups, and dependency loading. The encoding uses a compact node format with branch characters, value characters (leaf/bud/glob semantics), and jump offsets, all packed into a Java string's char sequence. Benchmarks show ClassNameTrie is nearly 5x faster than the old code-based approach on Java 8 during cold start, and faster than a classic radix trie due to cache locality. In a real Spring Boot application, class-name filtering reduced instrumented startup time by 20%, with ClassNameTrie adding another 1% and a follow-on known-types index adding 3%, totaling over 24% savings. The ClassNameTrie is open-sourced and now used in Datadog Live Debugger and CI Visibility as well.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.datadoghq.com/blog/engineering/improving-apm-java-startup-with-a-prefix-trie>

## Questions this post answers

### How much faster is a JVM constant-encoded prefix trie compared to a code-based class name matcher during JVM startup?

Encoding the prefix trie as a JVM string constant is nearly 5x faster than the old code-based matcher on Java 8 during cold start, and it also outperforms a classic radix trie due to its compact representation and cache locality. In a real Spring Boot application, switching from code-based matching to this encoding saved an additional 1% of instrumented startup time.

_Developers tuning JVM agent startup performance can find similar deep engineering breakdowns on daily.dev._

### How do you store a trie data structure as a single Java string constant instead of building it at runtime?

Each node is packed into a sequence of chars, where the first char gives the branch count, followed by sorted branch characters, then value characters encoding whether each branch is a leaf, bud, or inline-segment length, and finally jump offsets to child nodes or segments. Large offsets over 61,439 use a separate long-jump table, letting the whole trie load via a single ldc bytecode instruction with no I/O.

_Engineers designing low-overhead startup paths can track techniques like this trie encoding on daily.dev._

### How much can filtering classes by name reduce Java APM agent instrumented startup time?

Ignoring uninteresting classes by name prefix reduced instrumented startup time by 20% in a real-world Spring Boot application. Adding a known-types index mapping class names directly to numbered instrumentations saved a further 3%, bringing total savings from class-name filtering to more than 24% compared to not filtering by class name at all.

_Teams weighing instrumentation overhead against observability depth can follow these optimization trade-offs on daily.dev._

## Similar posts on daily.dev

- [Why Every JVM In Your Fleet Warms Up Alone](https://daily.dev/posts/why-every-jvm-in-your-fleet-warms-up-alone-airnow41v) · Foojay.io · 0 upvotes · 0 comments
- [A Deep Dive into JVM Start-up](https://daily.dev/posts/a-deep-dive-into-jvm-start-up-y56lgtork) · Baeldung · 9 upvotes · 0 comments
- [JEP 544: Ahead-of-Time Code Compilation](https://daily.dev/posts/jep-544-ahead-of-time-code-compilation-idncwszkw) · Awesome Java Newsletter · 0 upvotes · 0 comments

---

Tags: [#performance](https://daily.dev/tags/performance), [#java](https://daily.dev/tags/java), [#jvm](https://daily.dev/tags/jvm), [#apm](https://daily.dev/tags/apm)

[View this post on daily.dev](https://daily.dev/posts/how-we-improved-apm-java-startup-by-encoding-a-prefix-trie-as-a-jvm-constant-fogkaahmp)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"How we improved APM Java startup by encoding a prefix trie as a JVM constant","url":"https://daily.dev/posts/how-we-improved-apm-java-startup-by-encoding-a-prefix-trie-as-a-jvm-constant-fogkaahmp","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/how-we-improved-apm-java-startup-by-encoding-a-prefix-trie-as-a-jvm-constant-fogkaahmp"},"datePublished":"2026-08-11T15:17:35.093Z","dateModified":"2026-09-14T06:17:39.470Z","description":"Datadog's APM team reduced class-matching overhead by 30% over four years, with a key optimization being ClassNameTrie — a prefix trie encoded as a single JVM...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/669e3b1f4092cf1928cd5bb7a672be9f?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/669e3b1f4092cf1928cd5bb7a672be9f?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Datadog","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Datadog","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/8f9d7e3e4bd64bd7b9db9b2ea83e0c6a","url":"https://daily.dev/sources/datadog"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/how-we-improved-apm-java-startup-by-encoding-a-prefix-trie-as-a-jvm-constant-fogkaahmp","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"performance,java,jvm,apm","timeRequired":"PT12M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Datadog","item":"https://daily.dev/sources/datadog"},{"@type":"ListItem","position":3,"name":"How we improved APM Java startup by encoding a prefix trie as a JVM constant"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/how-we-improved-apm-java-startup-by-encoding-a-prefix-trie-as-a-jvm-constant-fogkaahmp#faq","mainEntity":[{"@type":"Question","name":"How much faster is a JVM constant-encoded prefix trie compared to a code-based class name matcher during JVM startup?","acceptedAnswer":{"@type":"Answer","text":"Encoding the prefix trie as a JVM string constant is nearly 5x faster than the old code-based matcher on Java 8 during cold start, and it also outperforms a classic radix trie due to its compact representation and cache locality. In a real Spring Boot application, switching from code-based matching to this encoding saved an additional 1% of instrumented startup time. Developers tuning JVM agent startup performance can find similar deep engineering breakdowns on daily.dev."}},{"@type":"Question","name":"How do you store a trie data structure as a single Java string constant instead of building it at runtime?","acceptedAnswer":{"@type":"Answer","text":"Each node is packed into a sequence of chars, where the first char gives the branch count, followed by sorted branch characters, then value characters encoding whether each branch is a leaf, bud, or inline-segment length, and finally jump offsets to child nodes or segments. Large offsets over 61,439 use a separate long-jump table, letting the whole trie load via a single ldc bytecode instruction with no I/O. Engineers designing low-overhead startup paths can track techniques like this trie encoding on daily.dev."}},{"@type":"Question","name":"How much can filtering classes by name reduce Java APM agent instrumented startup time?","acceptedAnswer":{"@type":"Answer","text":"Ignoring uninteresting classes by name prefix reduced instrumented startup time by 20% in a real-world Spring Boot application. Adding a known-types index mapping class names directly to numbered instrumentations saved a further 3%, bringing total savings from class-name filtering to more than 24% compared to not filtering by class name at all. Teams weighing instrumentation overhead against observability depth can follow these optimization trade-offs on daily.dev."}}]}
```

