Description

This is from the linked EPS case:

==============================

When 5.0 first introduced TObjectPtr, the guidance was that it would compile down to raw pointer access in Shipping builds to ensure identical performance.

Evidenced by the following quote from the documentation for 5.0:

UE5 introduces TObjectPtr, a template-based, 64-bit pointer system, as an optional replacement for raw object pointers in editor builds. This system adds dynamic resolution and access tracking in editor builds, while performing identically to raw pointers in non-editor builds.

In recent versions of the engine, this guarantee seems to have been silently dropped.

The introduction of incremental reachability analysis adds code to call ConditionallyMarkAsReachable, regardless of whether incremental GC is turned on.

This causes assembly instructions comparable to the following to be generated inline every time a TObjectPtr or TSubclassOf is assigned:

cmp byte ptr [UE::GC::GIsIncrementalReachabilityPending],r14b

je _____+16Fh

mov rcx,qword ptr [rbx+458h]

test rcx,rcx

je _____+16Fh

call UE::GC::MarkAsReachable

In our game, this adds several megabytes to our compiled binary size, putting pressure on the instruction cache and branch predictor.

Even though incremental GC is experimental and not even supported outside of single-threaded servers, right now every game is paying for the feature even when not enabled, due to `UE_OBJECT_PTR_GC_BARRIER` being unconditionally set to `1` in `ObjectPtr.h`.

My questions are the following:

  • It would be nice if this code was automatically compiled out when incremental GC is off, instead of us having to randomly find out about the define during profiling.
  • This seems to unconditionally apply to every TSubclassOf as well, even when used as a parameter/local variable and GC barriers are unnecessary.
  • Inlining the check to `GIsIncrementalReachabilityPending` makes sense, but it might be worth moving the null object check into `MarkAsReachable` itself, which would reduce the binary size cost of the repeatedly inlined code.
Steps to Reproduce

Suggested by Claude Opus 5.5 (jira-repro-steps-auditor skill), for questions reach out to feature SME

Steps to Repro:

  1. Sync UE5 Main at CL 58443255 or later and open the editor.
  2. Create a Blank Blueprint project.
  3. Platforms > Windows > Package Project, with the Development build configuration.
  4. Open Command Prompt in the packaged folder and run the game with a log window: <ProjectName>.exe -log
  5. In the game, press the ` key (above Tab) to open the console.
  6. Enter gc.AllowIncrementalReachability 1 and check the log window.
  7. Close the game. In the editor, open the Output Log, enter gc.AllowIncrementalReachability 1 in the Cmd box, and check the log.

Expected Results:

In the packaged game, the log window shows a LogGarbage warning: "Trying to set gc.AllowIncrementalReachability to 1 in a build with the GC barriers compiled out (see UE_WITH_GC_BARRIER). Incremental reachability is not supported." The game keeps running. In the editor, no such warning appears.

Have Comments or More Details?

There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-386406 in the post.

2
Login to Vote

Fixed
ComponentUE - Core - Systems
Affects Versions5.8
Target Fix5.9
Fix Commit58443255
CreatedJul 13, 2026
ResolvedSep 23, 2026
UpdatedOct 5, 2026
View Jira Issue