We’re seeing the Seeker stay in memory when destroyed, not 100% sure why that is, but we’ve worked around the issue for now by using AstarPath.StartPath instead of seeker-per-object
Here’s code to reproduce the issue:
using System;
using System.Collections;
using Pathfinding;
using UnityEngine;
using Random = UnityEngine.Random;
public class Test : MonoBehaviour {
public int TargetCount = 10000;
public int PerSecond = 100;
public int CurrentCount;
public int CompletedCount;
// Update is called once per frame
void Update() {
if (CurrentCount >= TargetCount) {
return;
}
for (int i = 0; i < Mathf.CeilToInt(PerSecond * Time.deltaTime); i++) {
StartCoroutine(Seek(i));
CurrentCount++;
if (CurrentCount == TargetCount) {
break;
}
}
}
IEnumerator Seek(int i) {
var go = new GameObject($"Seeker #{i}");
var seeker = go.AddComponent<Seeker>();
var modifier = go.AddComponent<RaycastModifier>();
modifier.useRaycasting = false;
modifier.useGraphRaycasting = true;
bool done = false;
void Callback(Path path) {
seeker.pathCallback -= Callback;
done = true;
}
seeker.pathCallback = Callback;
// wait a frame to give everything time to call Start and such
yield return null;
// path to somewhere random
var start = transform.position;
var dest = start + new Vector3(Random.Range(-10.0f, 10.0f), 0, Random.Range(-10.0f, 10.0f));
seeker.StartPath(start, dest);
// and then wait for the path to be done
while (!done) {
yield return null;
}
yield return null;
// destroy the seeker gameobject
Destroy(go);
CompletedCount++;
if (CompletedCount == TargetCount) {
yield return null;
// for good measure, just run the gc here to prove we are in fact leaking and
// not just waiting for gc to run
GC.Collect();
yield return null;
for (int j = 0; j < 10; j++) {
Debug.LogError("DONE!");
}
}
}
}
When then taking a snapshot of the project via the memory profiler package you should see seekers and related objects hanging around: https://share.dl.je/2020/11/2020-11-06_12-24-20_6AOtHhNVbU.png
This was tested in a build, so it’s not just a unity editor quirk