I am trying to make a function that can receive unlimited amount of arguments without crating GC.
I know that this can be done with the params
keyword but it creates GC. Also understand that you can pass array to to the function but I want to know if it is possible to pass unlimited method arguments without creating GC and without creating array or list and passing it to the List.
This is the example with the param
code:
void Update()
{
GameObject player1 = GameObject.Find("Player1");
GameObject player2 = GameObject.Find("Player2");
GameObject enemy1 = GameObject.Find("Enemy1");
GameObject enemy2 = GameObject.Find("Enemy2");
GameObject enemy3 = GameObject.Find("Enemy3");
Vector3 newPos = new Vector3(0, 0, 0);
moveObjects(newPos, 3f, player1, player2, enemy1, enemy2, enemy3);
}
void moveObjects(Vector3 newPos, float duration, params GameObject[] objs)
{
for (int i = 0; i < objs.Length; i++)
{
//StartCoroutine(moveToNewPos(objs[i].transform, newPos, duration));
}
}
When executed even with the StartCoroutine
function commented out, it allocates 80 bytes. At first, I thought this was happening because I used the foreach
loop then I changed that to a for
loop but it still creating GC then I realized that params GameObject[]
is causing it. See the Profiler below fore more visual information on this:
So, how can I create a method that takes unlimited arguments without generating GC?
Please ignore the use of GameObject.Find
function used in the Update
function. That's just used for an example to get the reference of Objects I want during run-time. I have a script implemented to handle that but not related what's in this question.
If you use params
and specify arguments in that way then yes, it will always create an array object.
If you want to avoid that, and if you don't need to worry about recursion or thread safety, you could keep a List<GameObject>
around and use the same list multiple times. For example:
private readonly List<GameObject> objectListCache = new List<GameObject>();
private void Update()
{
cachedObjectList.Clear();
cachedObjectList.Add(GameObject.Find("Player1"));
cachedObjectList.Add(GameObject.Find("Player2"));
cachedObjectList.Add(GameObject.Find("Enemy1"));
cachedObjectList.Add(GameObject.Find("Enemy2"));
cachedObjectList.Add(GameObject.Find("Enemy3"));
Vector3 newPos = new Vector3(0, 0, 0);
moveObjects(newPos, 3f, cachedObjectList);
cachedObjectList.Clear();
}
void MoveObjects(Vector3 newPos, float duration, List<GameObject> objs)
{
foreach (GameObject obj in objs)
{
// ...
}
}
When you clear the List<T>
that will set all the elements of the internal buffer to null, but won't discard the buffer - so it can be used again for the next Update
call without any allocation.
See more on this question at Stackoverflow