Skip to content

Commit 005505c

Browse files
ekcohLeoUnity
andauthored
FIX: Mitigate memory allocation driven by reflective introspection of binding types ISXB-1766 (#2285)
Co-authored-by: Leonardo Carneiro <leonardo@unity3d.com>
1 parent 83db18f commit 005505c

File tree

3 files changed

+49
-14
lines changed

3 files changed

+49
-14
lines changed

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ however, it has to be formatted properly to pass verification tests.
1919
### Fixed
2020
- An issue where a UITK MouseEvent was triggered when changing from Scene View to Game View in the Editor has been fixed. [ISXB-1671](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1671)
2121
- Fix documentation error in file AndroidGameController.cs mentioning a wrong controller. [DOCATT-9806]
22-
22+
- Deferred auto-registration of processors, interactions and composite binding types referenced by `InputActionAsset`
23+
to only happen once when an unresolved type reference is found in an action definition. This avoids reflective
24+
type loading from assemblies for all cases where the Input System is not extended. (ISXB-1766).
2325

2426
## [1.16.0] - 2025-11-10
2527

Packages/com.unity.inputsystem/InputSystem/InputManager.cs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,9 +1913,9 @@ private void InitializeActions()
19131913
internal void InitializeData()
19141914
{
19151915
m_Layouts.Allocate();
1916-
m_Processors.Initialize();
1917-
m_Interactions.Initialize();
1918-
m_Composites.Initialize();
1916+
m_Processors.Initialize(this);
1917+
m_Interactions.Initialize(this);
1918+
m_Composites.Initialize(this);
19191919
m_DevicesById = new Dictionary<int, InputDevice>();
19201920

19211921
// Determine our default set of enabled update types. By
@@ -2026,11 +2026,11 @@ internal void InitializeData()
20262026
composites.AddTypeRegistration("OneModifier", typeof(OneModifierComposite));
20272027
composites.AddTypeRegistration("TwoModifiers", typeof(TwoModifiersComposite));
20282028

2029-
// Register custom types by reflection
2030-
RegisterCustomTypes();
2029+
// ISXB-1766: Defer loading custom types by reflection unless we have to since referenced from
2030+
// .inputaction JSON assets. This is managed via TypeTable.cs.
20312031
}
20322032

2033-
void RegisterCustomTypes(Type[] types)
2033+
static void RegisterCustomTypes(Type[] types)
20342034
{
20352035
foreach (Type type in types)
20362036
{
@@ -2053,8 +2053,18 @@ void RegisterCustomTypes(Type[] types)
20532053
}
20542054
}
20552055

2056-
void RegisterCustomTypes()
2056+
private bool m_CustomTypesRegistered;
2057+
2058+
internal bool RegisterCustomTypes()
20572059
{
2060+
// If we have already attempted to register custom types, there is no need to reattempt since we
2061+
// would end up with the same result again. Only with a domain reload would the resulting types
2062+
// be different, and hence it is sufficient to use a static flag that we do not reset.
2063+
if (m_CustomTypesRegistered)
2064+
return false; // Already evaluated
2065+
2066+
m_CustomTypesRegistered = true;
2067+
20582068
k_InputRegisterCustomTypesMarker.Begin();
20592069

20602070
var inputSystemAssembly = typeof(InputProcessor).Assembly;
@@ -2079,11 +2089,13 @@ void RegisterCustomTypes()
20792089
}
20802090
catch (ReflectionTypeLoadException)
20812091
{
2082-
continue;
2092+
// Ignore exception
20832093
}
20842094
}
20852095

20862096
k_InputRegisterCustomTypesMarker.End();
2097+
2098+
return true; // Signal that custom types were extracted and registered.
20872099
}
20882100

20892101
internal void InstallRuntime(IInputRuntime runtime)
@@ -2164,6 +2176,9 @@ internal void UninstallGlobals()
21642176
InputControlLayout.s_CacheInstance = default;
21652177
InputControlLayout.s_CacheInstanceRef = 0;
21662178

2179+
// Invalidate type registrations
2180+
m_CustomTypesRegistered = false;
2181+
21672182
// Detach from runtime.
21682183
if (m_Runtime != null)
21692184
{

Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,16 @@ internal struct TypeTable
2525
public HashSet<InternedString> aliases;
2626
#endif
2727

28-
public void Initialize()
28+
// Strong coupling to Input Manager which is always the owner
29+
private InputManager m_Manager;
30+
31+
public void Initialize(InputManager manager)
2932
{
3033
table = new Dictionary<InternedString, Type>();
3134
#if UNITY_EDITOR
3235
aliases = new HashSet<InternedString>();
3336
#endif
37+
m_Manager = manager;
3438
}
3539

3640
public InternedString FindNameForType(Type type)
@@ -80,10 +84,24 @@ public Type LookupTypeRegistration(string name)
8084
if (table == null)
8185
throw new InvalidOperationException("Input System not yet initialized");
8286

83-
var internedName = new InternedString(name);
84-
if (table.TryGetValue(internedName, out var type))
85-
return type;
86-
return null;
87+
return TryLookupTypeRegistration(new InternedString(name));
88+
}
89+
90+
private Type TryLookupTypeRegistration(InternedString internedName)
91+
{
92+
if (!table.TryGetValue(internedName, out var type))
93+
{
94+
// Failed to look-up type, either type do not exist or it is a custom type that has not been registered.
95+
// Check whether we have attempted to load custom types and otherwise lazily load types only when
96+
// relevant and reattempt looking up type by name. (ISXB-1766)
97+
if (m_Manager != null)
98+
{
99+
if (m_Manager.RegisterCustomTypes())
100+
table.TryGetValue(internedName, out type);
101+
}
102+
}
103+
104+
return type;
87105
}
88106

89107
#if UNITY_EDITOR

0 commit comments

Comments
 (0)