Skip to content

[Enhancement] Eliminate per-RPC allocation from Logback status, TopicMessageType toLowerCase, and RemotingHelper eager evaluation #10490

Description

@wang-jiahua

Before Creating the Enhancement Request

  • I have confirmed that this should be classified as an enhancement rather than a bug/feature.

Summary

Three independent per-RPC/per-metrics micro-allocations can be eliminated to reduce unnecessary heap pressure:

  1. Logback BasicStatusManager — internal status events accumulate during XML configuration loading without being consumed.
  2. TopicMessageType.getMetricsValue() — allocates a new String on every call via value.toLowerCase().
  3. RemotingHelper.getRequestCodeDesc() / getResponseCodeDesc() — eagerly evaluates String.valueOf(code) in Map.getOrDefault() even on cache hit.

Motivation

JFR settings=profile on a broker under steady-state send load reveals these three allocation sites as recurring per-RPC waste:

  • Logback status events (InfoStatus, BodyEvent) accumulate in BasicStatusManager retained set (~655 KiB) despite never being queried in production. Adding NopStatusListener suppresses the callback overhead.
  • TopicMessageType.getMetricsValue() is called once per send for metrics labeling. The toLowerCase() result is deterministic per enum constant — caching it in the constructor avoids ~1 String + 1 byte[] per RPC.
  • RemotingHelper.getRequestCodeDesc() and getResponseCodeDesc() are called per RPC response. Java eagerly evaluates String.valueOf(code) as a method argument to Map.getOrDefault(), allocating a String even when the key exists in the map. A simple get() + null check eliminates this on the hot (cache-hit) path.

Combined, these save ~200–300 bytes per RPC with zero behavioral change.

Describe the Solution Youd Like

  1. Logback: Add <statusListener class="ch.qos.logback.core.status.NopStatusListener"/> after <configuration> in rmq.broker.logback.xml.

  2. TopicMessageType: Cache metricsValue as a final String field initialized in the enum constructor with Locale.ROOT. The getter returns the cached reference directly.

  3. RemotingHelper: Replace REQUEST_CODE_MAP.getOrDefault(code, String.valueOf(code)) with:

    String desc = REQUEST_CODE_MAP.get(code);
    return desc != null ? desc : String.valueOf(code);

    Same pattern for RESPONSE_CODE_MAP.

Describe Alternatives Youve Considered

  • Removing NopStatusListener: Considered using a conditional listener or loggerContext.getStatusManager().clear() in code. Rejected because the XML-level listener is simpler and doesnt require broker startup changes.
  • String.intern() for metrics values: Rejected due to global String table contention and lack of locale control.
  • computeIfAbsent for RemotingHelper: Overkill — the map is a static Map<Integer, String> populated at class load time. A null check is simpler and avoids lambda allocation.

Additional Context

PR: #10491

This PR is stacked on PR #10443 (AttributeKey statics) and will be rebased on develop after #10443 merges to show only the 3 files above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions