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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions