Skip to content

Commit 1edc2ab

Browse files
fix: Removed unnecessary GC Allocation [3527-Backport] (#3601)
Fix for [MTTB-85](https://jira.unity3d.com/browse/MTTB-85) removed the use of a foreach causing an unnecessary GC Allocation. Did a full sweep of internal `NetworkManager.ConnectedClientsIds` and replaced with either `for` loop or directly referencing the `NetworkConnectionManager.ConnectedClientIds`. ## Changelog - Fixed: Issue with unnecessary internal GC Allocations when using the `IReadOnlyList` `NetworkManager.ConnectedClientsIds` within a `foreach` statement by either replacing with a `for` loop or directly referencing the `NetworkConnectionManager.ConnectedClientIds`. ## Documentation - No documentation updates were required. ## Testing & QA [//]: # ( This section is REQUIRED and should describe how the changes were tested and how should they be tested when Playtesting for the release. It can range from "edge case covered by unit tests" to "manual testing required and new sample was added". Expectation is that PR creator does some manual testing and provides a summary of it here.) ### Functional Testing [//]: # (If checked, List manual tests that have been performed.) _Manual testing :_ - [X] `Manual testing done` - Tested manually before and after fix to confirm the allocation was present and then absent. _Automated tests:_ - [ ] `Covered by existing automated tests` - [ ] `Covered by new automated tests` _Does the change require QA team to:_ - [ ] `Review automated tests`? - [ ] `Execute manual tests`? If any boxes above are checked, please add QA as a PR reviewer. ## Backport This is the backport for #3527
1 parent a9a8868 commit 1edc2ab

File tree

12 files changed

+29
-22
lines changed

12 files changed

+29
-22
lines changed

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ Additional documentation and release notes are available at [Multiplayer Documen
1414

1515
### Fixed
1616

17-
- Removed allocation to the heap in NetworkBehaviourUpdate. (#3568)
17+
- Fixed issue with unnecessary internal GC Allocations when using the `IReadOnlyList` `NetworkManager.ConnectedClientsIds` within a `foreach` statement by either replacing with a `for` loop or directly referencing the `NetworkConnectionManager.ConnectedClientIds`. (#3601)
18+
- Fixed issue with allocation to the heap in NetworkBehaviourUpdate when there is nothing to be updated. (#3568)
1819
- Fixed issue where NetworkConfig.ConnectionData could cause the ConnectionRequestMessage to exceed the transport's MTU size and would result in a buffer overflow error. (#3565)
1920

21+
2022
### Changed
2123

2224

com.unity.netcode.gameobjects/Components/NetworkAnimator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ internal void CheckForAnimatorChanges()
961961
{
962962
// Just notify all remote clients and not the local server
963963
m_ClientSendList.Clear();
964-
foreach (var clientId in NetworkManager.ConnectedClientsIds)
964+
foreach (var clientId in NetworkManager.ConnectionManager.ConnectedClientIds)
965965
{
966966
if (clientId == NetworkManager.LocalClientId || !NetworkObject.Observers.Contains(clientId))
967967
{
@@ -1320,7 +1320,7 @@ private unsafe void SendAnimStateServerRpc(AnimationMessage animationMessage, Se
13201320
if (NetworkManager.ConnectedClientsIds.Count > (IsHost ? 2 : 1))
13211321
{
13221322
m_ClientSendList.Clear();
1323-
foreach (var clientId in NetworkManager.ConnectedClientsIds)
1323+
foreach (var clientId in NetworkManager.ConnectionManager.ConnectedClientIds)
13241324
{
13251325
if (clientId == serverRpcParams.Receive.SenderClientId || clientId == NetworkManager.ServerClientId || !NetworkObject.Observers.Contains(clientId))
13261326
{

com.unity.netcode.gameobjects/Runtime/Connection/NetworkConnectionManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,12 @@ internal void InvokeOnClientConnectedCallback(ulong clientId)
134134

135135
if (!NetworkManager.IsServer)
136136
{
137-
var peerClientIds = new NativeArray<ulong>(Math.Max(NetworkManager.ConnectedClientsIds.Count - 1, 0), Allocator.Temp);
137+
var peerClientIds = new NativeArray<ulong>(Math.Max(ConnectedClientIds.Count - 1, 0), Allocator.Temp);
138138
// `using var peerClientIds` or `using(peerClientIds)` renders it immutable...
139139
using var sentinel = peerClientIds;
140140

141141
var idx = 0;
142-
foreach (var peerId in NetworkManager.ConnectedClientsIds)
142+
foreach (var peerId in ConnectedClientIds)
143143
{
144144
if (peerId == NetworkManager.LocalClientId)
145145
{

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,10 +1252,10 @@ private void OnTransformParentChanged()
12521252

12531253
unsafe
12541254
{
1255-
var maxCount = NetworkManager.ConnectedClientsIds.Count;
1255+
var maxCount = NetworkManager.ConnectionManager.ConnectedClientIds.Count;
12561256
ulong* clientIds = stackalloc ulong[maxCount];
12571257
int idx = 0;
1258-
foreach (var clientId in NetworkManager.ConnectedClientsIds)
1258+
foreach (var clientId in NetworkManager.ConnectionManager.ConnectedClientIds)
12591259
{
12601260
if (Observers.Contains(clientId))
12611261
{

com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/BaseRpcTarget.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public abstract class BaseRpcTarget : IDisposable
1111
/// The <see cref="NetworkManager"/> instance which can be used to handle sending and receiving the specific target(s)
1212
/// </summary>
1313
protected NetworkManager m_NetworkManager;
14+
internal NetworkConnectionManager ConnectionManager;
1415
private bool m_Locked;
1516

1617
internal void Lock()
@@ -26,6 +27,7 @@ internal void Unlock()
2627
internal BaseRpcTarget(NetworkManager manager)
2728
{
2829
m_NetworkManager = manager;
30+
ConnectionManager = m_NetworkManager.ConnectionManager;
2931
}
3032

3133
/// <summary>

com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotMeRpcTarget.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message,
4343
}
4444
else
4545
{
46-
foreach (var clientId in m_NetworkManager.ConnectedClientsIds)
46+
foreach (var clientId in ConnectionManager.ConnectedClientIds)
4747
{
4848
if (clientId == behaviour.NetworkManager.LocalClientId)
4949
{

com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotOwnerRpcTarget.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message,
5555
}
5656
else
5757
{
58-
foreach (var clientId in m_NetworkManager.ConnectedClientsIds)
58+
foreach (var clientId in ConnectionManager.ConnectedClientIds)
5959
{
6060
if (clientId == behaviour.OwnerClientId)
6161
{

com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/NotServerRpcTarget.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ internal override void Send(NetworkBehaviour behaviour, ref RpcMessage message,
4444
}
4545
else
4646
{
47-
foreach (var clientId in m_NetworkManager.ConnectedClientsIds)
47+
foreach (var clientId in ConnectionManager.ConnectedClientIds)
4848
{
4949
if (clientId == NetworkManager.ServerClientId)
5050
{

com.unity.netcode.gameobjects/Runtime/Messaging/RpcTargets/RpcTarget.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,11 @@ public enum RpcTargetUse
107107
public class RpcTarget
108108
{
109109
private NetworkManager m_NetworkManager;
110+
private NetworkConnectionManager m_ConnectionManager;
110111
internal RpcTarget(NetworkManager manager)
111112
{
112113
m_NetworkManager = manager;
114+
m_ConnectionManager = manager.ConnectionManager;
113115

114116
Everyone = new EveryoneRpcTarget(manager);
115117
Owner = new OwnerRpcTarget(manager);
@@ -284,8 +286,9 @@ public BaseRpcTarget Not(ulong excludedClientId, RpcTargetUse use)
284286
target = m_CachedProxyRpcTargetGroup;
285287
}
286288
}
289+
287290
target.Clear();
288-
foreach (var clientId in m_NetworkManager.ConnectedClientsIds)
291+
foreach (var clientId in m_ConnectionManager.ConnectedClientIds)
289292
{
290293
if (clientId != excludedClientId)
291294
{
@@ -468,7 +471,7 @@ public BaseRpcTarget Not(NativeArray<ulong> excludedClientIds, RpcTargetUse use)
468471
asASet.Add(clientId);
469472
}
470473

471-
foreach (var clientId in m_NetworkManager.ConnectedClientsIds)
474+
foreach (var clientId in m_ConnectionManager.ConnectedClientIds)
472475
{
473476
if (!asASet.Contains(clientId))
474477
{
@@ -557,13 +560,13 @@ public BaseRpcTarget Not<T>(T excludedClientIds, RpcTargetUse use) where T : IEn
557560
}
558561
target.Clear();
559562

560-
using var asASet = new NativeHashSet<ulong>(m_NetworkManager.ConnectedClientsIds.Count, Allocator.Temp);
563+
using var asASet = new NativeHashSet<ulong>(m_ConnectionManager.ConnectedClientIds.Count, Allocator.Temp);
561564
foreach (var clientId in excludedClientIds)
562565
{
563566
asASet.Add(clientId);
564567
}
565568

566-
foreach (var clientId in m_NetworkManager.ConnectedClientsIds)
569+
foreach (var clientId in m_ConnectionManager.ConnectedClientIds)
567570
{
568571
if (!asASet.Contains(clientId))
569572
{

com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ internal NetworkSceneManager(NetworkManager networkManager)
829829
private void SceneManager_ActiveSceneChanged(Scene current, Scene next)
830830
{
831831
// If no clients are connected, then don't worry about notifications
832-
if (!(NetworkManager.ConnectedClientsIds.Count > (NetworkManager.IsHost ? 1 : 0)))
832+
if (!(NetworkManager.ConnectionManager.ConnectedClientIds.Count > (NetworkManager.IsHost ? 1 : 0)))
833833
{
834834
return;
835835
}
@@ -850,7 +850,7 @@ private void SceneManager_ActiveSceneChanged(Scene current, Scene next)
850850
var sceneEvent = BeginSceneEvent();
851851
sceneEvent.SceneEventType = SceneEventType.ActiveSceneChanged;
852852
sceneEvent.ActiveSceneHash = BuildIndexToHash[next.buildIndex];
853-
SendSceneEventData(sceneEvent.SceneEventId, NetworkManager.ConnectedClientsIds.Where(c => c != NetworkManager.ServerClientId).ToArray());
853+
SendSceneEventData(sceneEvent.SceneEventId, NetworkManager.ConnectionManager.ConnectedClientIds.Where(c => c != NetworkManager.ServerClientId).ToArray());
854854
EndSceneEvent(sceneEvent.SceneEventId);
855855
}
856856
}
@@ -1139,10 +1139,10 @@ private bool OnSceneEventProgressCompleted(SceneEventProgress sceneEventProgress
11391139
{
11401140
EventData = sceneEventData
11411141
};
1142-
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, NetworkManager.ConnectedClientsIds);
1142+
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, NetworkManager.ConnectionManager.ConnectedClientIds);
11431143

11441144
NetworkManager.NetworkMetrics.TrackSceneEventSent(
1145-
NetworkManager.ConnectedClientsIds,
1145+
NetworkManager.ConnectionManager.ConnectedClientIds,
11461146
(uint)sceneEventProgress.SceneEventType,
11471147
SceneNameFromHash(sceneEventProgress.SceneHash),
11481148
size);
@@ -1291,7 +1291,7 @@ private void OnSceneUnloaded(uint sceneEventId)
12911291
// Server sends the unload scene notification after unloading because it will despawn all scene relative in-scene NetworkObjects
12921292
// If we send this event to all clients before the server is finished unloading they will get warning about an object being
12931293
// despawned that no longer exists
1294-
SendSceneEventData(sceneEventId, NetworkManager.ConnectedClientsIds.Where(c => c != NetworkManager.ServerClientId).ToArray());
1294+
SendSceneEventData(sceneEventId, NetworkManager.ConnectionManager.ConnectedClientIds.Where(c => c != NetworkManager.ServerClientId).ToArray());
12951295

12961296
//Only if we are a host do we want register having loaded for the associated SceneEventProgress
12971297
if (SceneEventProgressTracking.ContainsKey(sceneEventData.SceneEventProgressId) && NetworkManager.IsHost)
@@ -2515,7 +2515,7 @@ internal void CheckForAndSendNetworkObjectSceneChanged()
25152515
// Some NetworkObjects still exist, send the message
25162516
var sceneEvent = BeginSceneEvent();
25172517
sceneEvent.SceneEventType = SceneEventType.ObjectSceneChanged;
2518-
SendSceneEventData(sceneEvent.SceneEventId, NetworkManager.ConnectedClientsIds.Where(c => c != NetworkManager.ServerClientId).ToArray());
2518+
SendSceneEventData(sceneEvent.SceneEventId, NetworkManager.ConnectionManager.ConnectedClientIds.Where(c => c != NetworkManager.ServerClientId).ToArray());
25192519
EndSceneEvent(sceneEvent.SceneEventId);
25202520
}
25212521

0 commit comments

Comments
 (0)