{"id":232642,"date":"2025-11-20T08:34:32","date_gmt":"2025-11-20T16:34:32","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/java\/?p=232642"},"modified":"2025-12-11T12:28:28","modified_gmt":"2025-12-11T20:28:28","slug":"from-complexity-to-simplicity-intelligent-jvm-optimizations-on-azure","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/java\/from-complexity-to-simplicity-intelligent-jvm-optimizations-on-azure\/","title":{"rendered":"From Complexity to Simplicity: Intelligent JVM Optimizations on Azure"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>As cloud-native architectures scale across thousands of containers and virtual machines, Java performance tuning has become more distributed, complex, and error-prone than ever. As highlighted in our <a href=\"https:\/\/aka.ms\/jaz-publicpreview-blog\">public preview announcement<\/a>, traditional JVM optimization relied on expert, centralized operator teams manually tuning flags and heap sizes for large application servers. This approach simply doesn\u2019t scale in today\u2019s highly dynamic environments, where dozens\u2014or even hundreds\u2014of teams deploy cloud-native JVM workloads across diverse infrastructure.<\/p>\n<p>To address this, Microsoft built Azure Command Launcher for Java (<span style=\"font-family: courier new, courier, monospace;\"><code>jaz<\/code><\/span>), a lightweight command-line tool that wraps and invokes <code>java<\/code> (e.g., <code>jaz -jar myapp.jar<\/code>). This drop-in command automatically tunes your JVM across dedicated or resource-constrained environments, providing safe, intelligent, and observable optimization out of the box.<\/p>\n<h2>Why Automated Tuning Matters<\/h2>\n<p>Designed\u00a0for dedicated cloud environments\u2014whether running a single workload in a container or on a virtual machine\u2014Azure Command Launcher for Java acts as a fully resource-aware optimizer that adapts seamlessly across both deployment models.<\/p>\n<p>The goal is to make JVM optimization effortless and predictable by replacing one-off manual tuning with intelligent, resource-aware behavior that just works. Where traditional tuning demanded deep expertise, careful experimentation, and operational risk, the tool delivers adaptive optimization that stays consistent across architectures, environments, and workload patterns.<\/p>\n<h2>The Complexity of Manual JVM Tuning<\/h2>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table class=\"w-fit min-w-(--thread-content-width)\" style=\"width: 100%;\">\n<thead>\n<tr>\n<th><strong>Traditional Approach<\/strong><\/th>\n<th><strong><code>jaz<\/code> Approach<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Build-time optimization and custom builds<\/td>\n<td>Runtime tuning that adapts to any Java app<\/td>\n<\/tr>\n<tr>\n<td>Requires JVM expertise and manual experimentation<\/td>\n<td>Intelligent heuristics detect and optimize safely<\/td>\n<\/tr>\n<tr>\n<td>Configuration drift across environments<\/td>\n<td>Consistent, resource-aware behavior<\/td>\n<\/tr>\n<tr>\n<td>High operational risk<\/td>\n<td>Safe rollback and zero configuration risk<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>By replacing static configuration with dynamic, resource-aware tuning, <code>jaz<\/code> simplifies Java performance optimization across all Azure compute platforms.<\/p>\n<h2>How It Works: Safe, Smart, and Observable<\/h2>\n<h3>Safe by Default<\/h3>\n<p>The tool preserves user-provided JVM configuration wherever applicable.<\/p>\n<p>By default, the environment variable <code>JAZ_IGNORE_USER_TUNING<\/code> is set to <code>0<\/code>, which means user-specified flags such as <code>-Xmx<\/code>, <code>-Xms<\/code>, and other tuning options are honored.<\/p>\n<p>If <code>JAZ_IGNORE_USER_TUNING=1<\/code> is set, the tool ignores most options beginning with <code>-X<\/code> to allow full optimization. As an exception, selected diagnostic and logging flags (e.g. <code>-Xlog<\/code>) are always passed through to the JVM.<\/p>\n<p>Example (default behavior with user tuning preserved):<\/p>\n<p><code>jaz -Xmx2g -jar myapp.jar<\/code><\/p>\n<p>In this mode, the tool:<\/p>\n<ul>\n<li>Detects user-provided JVM flags and avoids conflicts<\/li>\n<li>Applies optimizations only when safe<\/li>\n<li>Guarantees no behavioral regressions in production<\/li>\n<\/ul>\n<h3>Smart Optimization<\/h3>\n<p>Beyond preserving user input, the tool performs resource-aware heap sizing using system or cgroup memory limits. It also detects the JDK version to enable vendor- and version-specific optimizations\u2014including enhancements available in Microsoft Build of OpenJDK, Eclipse Temurin, and others.<\/p>\n<p>This ensures consistent, cross-platform behavior across both x64 and ARM64 architectures.<\/p>\n<h3>Observability Without Overhead<\/h3>\n<p>The tool introduces adaptive telemetry designed to maximize inference while minimizing interference.<\/p>\n<blockquote><p><strong>Core principle<\/strong>: more insight, less intrusion.<\/p><\/blockquote>\n<p data-start=\"1711\" data-end=\"1965\">Telemetry is used internally today to guide safe optimization decisions. The system automatically adjusts data collection depth across runtime phases (startup and steady state), providing production-grade visibility without impacting application performance.<\/p>\n<p data-start=\"1967\" data-end=\"2099\">Future phases will extend this with event-driven telemetry, including anomaly-triggered sampling for deeper insight when needed.<\/p>\n<h2>Evolution of Memory Management<\/h2>\n<p>The tool&#8217;s memory-management approach has evolved beyond conservative, resource-aware heuristics such as the default ergonomics in OpenJDK. It now applies an adaptive model that incorporates JDK-specific knowledge to deliver stable, efficient behavior across diverse cloud environments. Each stage builds on production learnings to improve predictability and performance.<\/p>\n<h3>Stage 1: Resource-Aware Foundations<\/h3>\n<p>The initial implementation established predictable memory behavior for both containerized and VM-based workloads.<\/p>\n<ul>\n<li>Dynamically sized the Java heap based on system or cgroup memory limits<\/li>\n<li>Tuned garbage-collection ergonomics for cloud usage patterns<\/li>\n<li>Prioritized safety and consistency through conservative, production-first defaults<\/li>\n<\/ul>\n<h3>Stage 2: JDK-Aware Hybrid Optimization (Current)<\/h3>\n<p>The version available in Public Preview extends this foundation with JDK introspection and vendor-specific awareness.<\/p>\n<ul>\n<li>Detects the JDK version and applies the corresponding tuning profile<\/li>\n<li>Enables optimizations for Microsoft Build of OpenJDK when present in the path, leveraging its advanced memory-management features to enable pause-less memory reclamation, typically reclaiming 318\u2013708 MB per cycle without adding latency<\/li>\n<li>Falls back to proven, broadly compatible strategies for other JDK distributions, maintaining consistent results across platforms<\/li>\n<li>Maintains stable throughput and predictable latency across VM and container environments by combining static safety heuristics with adaptive memory behavior<\/li>\n<\/ul>\n<p>This integration also informs the tool\u2019s telemetry model, where the same balance between visibility and performance guides data-collection strategy.<\/p>\n<h2>The Inference vs Interference Matrix<\/h2>\n<p>In observability systems, <em>inference<\/em> (the ability to gain insight) and <em>interference<\/em> (the performance impact of measurement) are always in tension. The tool\u2019s telemetry model balances these forces by adjusting its sampling depth based on runtime phase and workload stability.<\/p>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table class=\"w-fit min-w-(--thread-content-width)\" style=\"width: 100%;\">\n<thead>\n<tr>\n<th><strong>Telemetry Mode<\/strong><\/th>\n<th><strong>Insight (Inference)<\/strong><\/th>\n<th><strong>Runtime Impact (Interference)<\/strong><\/th>\n<th><strong>Use Case<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>High-Frequency<\/td>\n<td>Deep event correlation<\/td>\n<td>Noticeable overhead<\/td>\n<td>Startup diagnostics<\/td>\n<\/tr>\n<tr>\n<td>Low-Frequency<\/td>\n<td>Basic trend observation<\/td>\n<td>Negligible overhead<\/td>\n<td>Steady-state monitoring<\/td>\n<\/tr>\n<tr>\n<td>Adaptive (tool)<\/td>\n<td>Critical metrics collected on demand<\/td>\n<td>Minimal overhead<\/td>\n<td>Production optimization<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>A useful comparison is Native Memory Tracking (NMT) in the JDK. While NMT exposes multiple levels of visibility into native memory usage (<code>summary<\/code>, <code>detail<\/code>, or <code>off<\/code>), most production systems rely on <em data-start=\"1324\" data-end=\"1333\">summary<\/em> mode for stability. Similarly, the tool embraces this tiered approach to observability but applies it dynamically by adjusting telemetry intensity rather than relying on static configuration.<\/p>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table class=\"w-fit min-w-(--thread-content-width)\" style=\"width: 100%;\">\n<thead>\n<tr>\n<th><strong>Phase<\/strong><\/th>\n<th><strong>Data Collection Depth<\/strong><\/th>\n<th><strong>Inference Level<\/strong><\/th>\n<th><strong>Interference Level<\/strong><\/th>\n<th><strong>Comparable NMT Concept<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Startup<\/td>\n<td>Focused sampling of GC and heap sizing<\/td>\n<td>High<\/td>\n<td>Moderate<\/td>\n<td><code>summary<\/code> with higher granularity<\/td>\n<\/tr>\n<tr>\n<td>Steady-State<\/td>\n<td>Aggregated metrics and key anomalies<\/td>\n<td>Medium<\/td>\n<td>Low<\/td>\n<td><code>summary<\/code><\/td>\n<\/tr>\n<tr>\n<td>Future (Event-Driven)<\/td>\n<td>Planned reactive sampling<\/td>\n<td>Targeted<\/td>\n<td>Minimal<\/td>\n<td>Conceptually <code>detail<\/code>-on-demand<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>The following visualizations illustrate how telemetry tracks memory behavior in sync with its adaptive sampling cadence. As the runtime transitions from startup to steady state, the tool automatically increases the time between samples\u2014reducing interference while preserving meaningful visibility into trends.<\/p>\n<p><figure id=\"attachment_232677\" aria-labelledby=\"figcaption_attachment_232677\" class=\"wp-caption alignnone\" ><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145813.webp\"><img decoding=\"async\" class=\"wp-image-232677 size-full\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145813.webp\" alt=\"Figure 1 shows how the interval between telemetry samples (Sample \u0394t) increases as the runtime stabilizes. Both Process A and Process B exhibit the same pattern: a high-frequency sampling phase during startup followed by a steady-state phase with larger, consistent sampling intervals. This adaptive behavior reduces interference while maintaining meaningful visibility into runtime behavior.\" width=\"1528\" height=\"1099\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145813.webp 1528w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145813-300x216.webp 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145813-1024x737.webp 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145813-768x552.webp 768w\" sizes=\"(max-width: 1528px) 100vw, 1528px\" \/><\/a><figcaption id=\"figcaption_attachment_232677\" class=\"wp-caption-text\">Figure 1: Adaptive Telemetry Sampling Over Time<\/figcaption><\/figure><\/p>\n<p data-start=\"2509\" data-end=\"2736\">Figure 1 shows how the interval between telemetry samples (Sample \u0394t) increases as the runtime stabilizes. Both Process A and Process B exhibit the same pattern: a high-frequency sampling phase during startup followed by a steady-state phase with larger, consistent sampling intervals. This adaptive behavior reduces interference while maintaining meaningful visibility into runtime behavior.<\/p>\n<p><figure id=\"attachment_232699\" aria-labelledby=\"figcaption_attachment_232699\" class=\"wp-caption alignnone\" ><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-200913.webp\"><img decoding=\"async\" class=\"wp-image-232699 size-full\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-200913.webp\" alt=\"Scatter plot showing the resident set size (RSS) of the Java process in gigabytes over time. The chart displays two runs, each beginning with allocation growth during warmup and stabilizing at a steady-state plateau. The data points are collected using adaptive telemetry, which increases sampling intervals as the runtime stabilizes, providing visibility into memory behavior with minimal performance impact.\" width=\"1355\" height=\"979\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-200913.webp 1355w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-200913-300x217.webp 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-200913-1024x740.webp 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-200913-768x555.webp 768w\" sizes=\"(max-width: 1355px) 100vw, 1355px\" \/><\/a><figcaption id=\"figcaption_attachment_232699\" class=\"wp-caption-text\">Figure 2: Java Process Memory Utilization Observed Through Adaptive Telemetry<\/figcaption><\/figure><\/p>\n<p data-start=\"2738\" data-end=\"2941\">Figure 2 shows the resident set size (RSS) of the Java process in GB, captured through adaptive telemetry. The visualization highlights the expected growth during warmup and stabilization during steady state. By adjusting sampling frequency intelligently, the tool provides production-grade observability of memory behavior without disrupting application performance or exceeding resource budgets.<\/p>\n<h2 data-start=\"284\" data-end=\"310\"><strong data-start=\"286\" data-end=\"310\">Benchmark Validation<\/strong><\/h2>\n<h3 data-start=\"312\" data-end=\"340\"><strong data-start=\"316\" data-end=\"340\">SPEC JBB2015 Results<\/strong><\/h3>\n<p data-start=\"342\" data-end=\"429\"><span style=\"color: #008080;\"><em>All SPEC JBB measurements in this study were run on Azure Linux\/Arm64 virtual machines.<\/em><\/span><\/p>\n<p><figure id=\"attachment_232678\" aria-labelledby=\"figcaption_attachment_232678\" class=\"wp-caption alignnone\" ><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145648.webp\"><img decoding=\"async\" class=\"wp-image-232678 size-full\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145648.webp\" alt=\"Bar chart comparing performance improvements from using jaz versus default JVM ergonomics on SPEC JBB2015, showing ~17\u201318% peak throughput gains and ~6\u201310% SLA gains depending on JDK.\" width=\"1579\" height=\"862\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145648.webp 1579w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145648-300x164.webp 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145648-1024x559.webp 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145648-768x419.webp 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-145648-1536x839.webp 1536w\" sizes=\"(max-width: 1579px) 100vw, 1579px\" \/><\/a><figcaption id=\"figcaption_attachment_232678\" class=\"wp-caption-text\">Figure 3: Relative Performance Improvement vs. Out-of-the-Box JVM Ergonomics (SPEC JBB2015)<\/figcaption><\/figure><\/p>\n<ul data-start=\"520\" data-end=\"1083\">\n<li data-start=\"520\" data-end=\"665\">\n<p data-start=\"522\" data-end=\"665\">The tool delivers double-digit peak throughput gains across all configurations tested\u2014well over <strong data-start=\"618\" data-end=\"625\">17%<\/strong> relative to out-of-the-box JVM ergonomics<\/p>\n<\/li>\n<li data-start=\"666\" data-end=\"991\">\n<p data-start=\"668\" data-end=\"991\">SLA-constrained performance improves as well, with the largest gains observed when paired with the Microsoft Build of OpenJDK (around <strong>10%<\/strong> in our tests)<\/p>\n<\/li>\n<\/ul>\n<blockquote><p><em data-start=\"830\" data-end=\"989\">In SPEC JBB2015, SLA performance represents latency-sensitive throughput\u2014how much work is sustained while meeting service-level response-time requirements.<\/em><\/p><\/blockquote>\n<ul data-start=\"520\" data-end=\"1083\">\n<li data-start=\"992\" data-end=\"1083\">\n<p data-start=\"994\" data-end=\"1083\">No regressions or stability issues were observed across repeated trials and JDK versions<\/p>\n<\/li>\n<\/ul>\n<h3 data-start=\"1090\" data-end=\"1131\"><strong data-start=\"1094\" data-end=\"1131\">Spring PetClinic REST API Results<\/strong><\/h3>\n<p data-start=\"1133\" data-end=\"1260\"><span style=\"color: #008080;\"><em>These measurements were run in containers with the tool applying cgroup-aware ergonomics under fixed CPU and memory limits.<\/em><\/span><\/p>\n<p data-start=\"1262\" data-end=\"1706\">The Spring PetClinic REST backend provides a lighter-weight request\/response workload that complements SPEC JBB2015 rather than replacing it. It exposes CRUD endpoints for owners, pets, vets, visits, pet types, and specialties (GET\/POST\/PUT\/DELETE), documented via Swagger\/OpenAPI, and backed by H2 by default. The repository includes Apache JMeter test plans under <code data-start=\"1603\" data-end=\"1620\">src\/test\/jmeter<\/code>, which we run headless to generate steady read\/write traffic across the API surfaces.<\/p>\n<p data-start=\"1262\" data-end=\"1706\">To evaluate stability under resource contention, we also ran <code>stress-ng<\/code> in a companion container to introduce CPU and memory pressure alongside the JMeter-driven workload.<\/p>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table class=\"w-fit min-w-(--thread-content-width)\" style=\"width: 100%;\" data-start=\"1708\" data-end=\"2165\">\n<thead data-start=\"1708\" data-end=\"1774\">\n<tr data-start=\"1708\" data-end=\"1774\">\n<th data-start=\"1708\" data-end=\"1733\" data-col-size=\"sm\"><strong data-start=\"1710\" data-end=\"1732\">Performance Domain<\/strong><\/th>\n<th data-start=\"1733\" data-end=\"1746\" data-col-size=\"sm\"><strong data-start=\"1735\" data-end=\"1745\">Impact<\/strong><\/th>\n<th data-start=\"1746\" data-end=\"1774\" data-col-size=\"sm\"><strong data-start=\"1748\" data-end=\"1772\">Stability Assessment<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody data-start=\"1843\" data-end=\"2165\">\n<tr data-start=\"1843\" data-end=\"1914\">\n<td data-start=\"1843\" data-end=\"1864\" data-col-size=\"sm\">Mean Response Time<\/td>\n<td data-col-size=\"sm\" data-start=\"1864\" data-end=\"1883\">1\u20135% improvement<\/td>\n<td data-col-size=\"sm\" data-start=\"1883\" data-end=\"1914\">Consistent across scenarios<\/td>\n<\/tr>\n<tr data-start=\"1915\" data-end=\"1985\">\n<td data-start=\"1915\" data-end=\"1940\" data-col-size=\"sm\">Tail Latency (90\u201399th)<\/td>\n<td data-col-size=\"sm\" data-start=\"1940\" data-end=\"1958\">Neutral\/minimal<\/td>\n<td data-col-size=\"sm\" data-start=\"1958\" data-end=\"1985\">Maintained under stress\u2014including stress-ng<\/td>\n<\/tr>\n<tr data-start=\"1986\" data-end=\"2050\">\n<td data-start=\"1986\" data-end=\"2008\" data-col-size=\"sm\">Throughput Capacity<\/td>\n<td data-col-size=\"sm\" data-start=\"2008\" data-end=\"2025\">No degradation<\/td>\n<td data-col-size=\"sm\" data-start=\"2025\" data-end=\"2050\">Scales with resources<\/td>\n<\/tr>\n<tr data-start=\"2051\" data-end=\"2103\">\n<td data-start=\"2051\" data-end=\"2071\" data-col-size=\"sm\">Stress Resilience<\/td>\n<td data-col-size=\"sm\" data-start=\"2071\" data-end=\"2083\">Excellent<\/td>\n<td data-col-size=\"sm\" data-start=\"2083\" data-end=\"2103\">Production-ready<\/td>\n<\/tr>\n<tr data-start=\"2104\" data-end=\"2165\">\n<td data-start=\"2104\" data-end=\"2124\" data-col-size=\"sm\">Memory Efficiency<\/td>\n<td data-col-size=\"sm\" data-start=\"2124\" data-end=\"2141\">Resource-aware<\/td>\n<td data-col-size=\"sm\" data-start=\"2141\" data-end=\"2165\">Validated from 2\u20138GB<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In other words, the tool is effectively throughput-neutral on this microservice workload while delivering small improvements in mean response time and keeping tail latency and stability intact\u2014even when additional load is introduced via <code data-start=\"2095\" data-end=\"2106\">stress-ng<\/code>.<\/p>\n<blockquote><p>Taken together, the SPEC JBB2015 and Spring PetClinic REST results confirm that the tool enhances throughput, preserves tail latency, and maintains robust performance across both VM-based and containerized deployments\u2014even under additional system pressure.<\/p><\/blockquote>\n<\/div>\n<\/div>\n<h2 data-start=\"2339\" data-end=\"2372\"><strong data-start=\"2341\" data-end=\"2372\">Enterprise Deployment Model<\/strong><\/h2>\n<p data-start=\"2374\" data-end=\"2467\">The tool supports a safe, incremental adoption strategy designed for production environments:<\/p>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table class=\"w-fit min-w-(--thread-content-width)\" style=\"width: 100%;\" data-start=\"2469\" data-end=\"2837\">\n<thead data-start=\"2469\" data-end=\"2536\">\n<tr data-start=\"2469\" data-end=\"2536\">\n<th data-start=\"2469\" data-end=\"2481\" data-col-size=\"sm\"><strong data-start=\"2471\" data-end=\"2480\">Phase<\/strong><\/th>\n<th data-start=\"2481\" data-end=\"2496\" data-col-size=\"sm\"><strong data-start=\"2483\" data-end=\"2495\">Approach<\/strong><\/th>\n<th data-start=\"2496\" data-end=\"2518\" data-col-size=\"sm\"><strong data-start=\"2498\" data-end=\"2517\">Command Example<\/strong><\/th>\n<th data-start=\"2518\" data-end=\"2536\" data-col-size=\"sm\"><strong data-start=\"2520\" data-end=\"2534\">Risk Level<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody data-start=\"2606\" data-end=\"2837\">\n<tr data-start=\"2606\" data-end=\"2687\">\n<td data-start=\"2606\" data-end=\"2620\" data-col-size=\"sm\">Coexistence<\/td>\n<td data-col-size=\"sm\" data-start=\"2620\" data-end=\"2646\">Respect existing tuning<\/td>\n<td data-col-size=\"sm\" data-start=\"2646\" data-end=\"2676\"><code data-start=\"2648\" data-end=\"2675\">jaz -Xmx2g -jar myapp.jar<\/code><\/td>\n<td data-col-size=\"sm\" data-start=\"2676\" data-end=\"2687\">Minimal<\/td>\n<\/tr>\n<tr data-start=\"2688\" data-end=\"2755\">\n<td data-start=\"2688\" data-end=\"2703\" data-col-size=\"sm\">Optimization<\/td>\n<td data-col-size=\"sm\" data-start=\"2703\" data-end=\"2725\">Remove manual flags<\/td>\n<td data-col-size=\"sm\" data-start=\"2725\" data-end=\"2748\"><code data-start=\"2727\" data-end=\"2747\">jaz -jar myapp.jar<\/code><\/td>\n<td data-col-size=\"sm\" data-start=\"2748\" data-end=\"2755\">Low<\/td>\n<\/tr>\n<tr data-start=\"2756\" data-end=\"2837\">\n<td data-start=\"2756\" data-end=\"2769\" data-col-size=\"sm\">Validation<\/td>\n<td data-col-size=\"sm\" data-start=\"2769\" data-end=\"2792\">Verify tuning safely<\/td>\n<td data-col-size=\"sm\" data-start=\"2792\" data-end=\"2829\"><code data-start=\"2794\" data-end=\"2828\">JAZ_DRY_RUN=1 jaz -jar myapp.jar<\/code><\/td>\n<td data-col-size=\"sm\" data-start=\"2829\" data-end=\"2837\">Zero<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p data-start=\"2839\" data-end=\"2941\">This phased design lets teams adopt the tool at their own pace\u2014and roll back at any time without risk.<\/p>\n<h2 data-start=\"2948\" data-end=\"2976\"><strong data-start=\"2950\" data-end=\"2976\">Technical Architecture<\/strong><\/h2>\n<p data-start=\"2978\" data-end=\"3282\">When invoked, the launcher detects the runtime environment and JDK version, applies resource-aware JVM configuration, and launches the optimized JVM in which the application executes. Built-in telemetry operates with low overhead, providing observability without affecting startup or runtime performance.<\/p>\n<p><figure id=\"attachment_232683\" aria-labelledby=\"figcaption_attachment_232683\" class=\"wp-caption alignnone\" ><a href=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-154925.webp\"><img decoding=\"async\" class=\"wp-image-232683 size-full\" src=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-154925.webp\" alt=\"Figure 4 illustrates the end-to-end lifecycle of jaz during application startup and execution. The tool performs an instant setup phase\u2014detecting the environment and JDK version, applying resource-aware configuration, and preparing safe JVM arguments\u2014all within milliseconds. It then launches the optimized JVM, after which the Java application begins execution in a tuned environment. During the continuous runtime phase, low-overhead, event-driven telemetry runs concurrently, providing observability with minimal interference.\" width=\"1618\" height=\"756\" srcset=\"https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-154925.webp 1618w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-154925-300x140.webp 300w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-154925-1024x478.webp 1024w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-154925-768x359.webp 768w, https:\/\/devblogs.microsoft.com\/java\/wp-content\/uploads\/sites\/51\/2025\/11\/Screenshot-2025-11-19-154925-1536x718.webp 1536w\" sizes=\"(max-width: 1618px) 100vw, 1618px\" \/><\/a><figcaption id=\"figcaption_attachment_232683\" class=\"wp-caption-text\">Figure 4: The <code>jaz<\/code> runtime lifecycle showing instant setup, JVM bring-up, and continuous telemetry<\/figcaption><\/figure><\/p>\n<p>Figure 4 illustrates the end-to-end lifecycle of <code>jaz<\/code> during application startup and execution. The tool performs an instant setup phase\u2014detecting the environment and JDK version, applying resource-aware configuration, and preparing safe JVM arguments\u2014all within milliseconds. It then launches the optimized JVM, after which the Java application begins execution in a tuned environment. During the continuous runtime phase, low-overhead, event-driven telemetry runs concurrently, providing observability with minimal interference.<\/p>\n<h2 data-start=\"3762\" data-end=\"3779\"><strong data-start=\"3764\" data-end=\"3779\">Get Started<\/strong><\/h2>\n<div class=\"contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary\">\n<div class=\"overflow-y-auto p-4\" dir=\"ltr\">\n<pre class=\"prettyprint language-default\"><code class=\"language-default\"># Replace existing java command\r\njava -Xmx512m -jar myapp.jar \r\n\r\n# With jaz onboarded\r\njaz -Xmx512m -jar myapp.jar\r\n\r\n# Validate configuration without deployment impact\r\nJAZ_DRY_RUN=1 jaz -Xmx512m -jar myapp.jar\r\n\r\n# Override user-provided tuning flags and let jaz tune for you\r\nJAZ_IGNORE_USER_TUNING=1 jaz -Xmx512m -jar myapp.jar\r\n<\/code><\/pre>\n<p>Azure Command Launcher for Java is available in public preview. Start simplifying Java performance tuning across your Azure environments today.<\/p>\n<\/div>\n<\/div>\n<h2 data-start=\"4267\" data-end=\"4285\"><strong data-start=\"4269\" data-end=\"4285\">Key Benefits<\/strong><\/h2>\n<ul data-start=\"4287\" data-end=\"4504\">\n<li data-start=\"4287\" data-end=\"4335\">\n<p data-start=\"4289\" data-end=\"4335\">Immediate throughput improvements (<strong data-start=\"4324\" data-end=\"4332\">17%+<\/strong>)<\/p>\n<\/li>\n<li data-start=\"4336\" data-end=\"4387\">\n<p data-start=\"4338\" data-end=\"4387\">Consistent, resource-aware behavior across JDKs<\/p>\n<\/li>\n<li data-start=\"4388\" data-end=\"4424\">\n<p data-start=\"4390\" data-end=\"4424\">Safe, incremental adoption model<\/p>\n<\/li>\n<li data-start=\"4425\" data-end=\"4504\">\n<p data-start=\"4427\" data-end=\"4504\">Foundation for adaptive, self-optimizing behavior through runtime awareness<\/p>\n<\/li>\n<\/ul>\n<blockquote>\n<p data-start=\"4506\" data-end=\"4721\"><em>While telemetry is currently used only to improve the launcher internally, it lays the groundwork for future self-healing features that can inform runtime components such as GC ergonomics and heap-sizing heuristics.<\/em><\/p>\n<\/blockquote>\n<hr data-start=\"4723\" data-end=\"4726\" \/>\n<p data-start=\"4728\" data-end=\"4903\">Azure Command Launcher for Java turns JVM optimization from a specialized task into a built-in capability\u2014bringing Java simplicity, safety, and performance to the Azure cloud.<\/p>\n<p data-start=\"4905\" data-end=\"5077\">For installation, configuration, supported JDKs, and environment variables, see the Microsoft Learn documentation:<br data-start=\"5019\" data-end=\"5022\" \/><strong data-start=\"5022\" data-end=\"5077\"><a class=\"decorated-link\" href=\"https:\/\/learn.microsoft.com\/en-us\/java\/jaz\/overview\" target=\"_new\" rel=\"noopener\" data-start=\"5024\" data-end=\"5075\">https:\/\/learn.microsoft.com\/en-us\/java\/jaz\/overview<\/a><\/strong><\/p>\n<p data-start=\"5079\" data-end=\"5251\">A forthcoming performance analysis blog will present detailed results from extended performance testing, covering heap and GC behavior, and scaling trends across Azure VMs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction As cloud-native architectures scale across thousands of containers and virtual machines, Java performance tuning has become more distributed, complex, and error-prone than ever. As highlighted in our public preview announcement, traditional JVM optimization relied on expert, centralized operator teams manually tuning flags and heap sizes for large application servers. This approach simply doesn\u2019t scale [&hellip;]<\/p>\n","protected":false},"author":9384,"featured_media":227205,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[844,1,249],"tags":[13,751,248,26],"class_list":["post-232642","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-java","category-openjdk","tag-azure","tag-garbage-collection","tag-java","tag-performance"],"acf":[],"blog_post_summary":"<p>Introduction As cloud-native architectures scale across thousands of containers and virtual machines, Java performance tuning has become more distributed, complex, and error-prone than ever. As highlighted in our public preview announcement, traditional JVM optimization relied on expert, centralized operator teams manually tuning flags and heap sizes for large application servers. This approach simply doesn\u2019t scale [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/232642","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/users\/9384"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/comments?post=232642"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/posts\/232642\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media\/227205"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/media?parent=232642"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/categories?post=232642"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/java\/wp-json\/wp\/v2\/tags?post=232642"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}