Performance gets worse over time [Updated]

UPDATE 3

You know, sometimes we’re too clever for our own good. After spending a day convinced that my issue was due to animations not being unloaded out of memory, I went back to the Garbage Collector idea. And while I’m not convinced that it’s (directly) GC led me to discover what’s causing my issue where my game’s framerate slowly got really sluggish over time: my save script.
The way the script is supposed to work the game should autosave every 35 seconds. Testing how garbage collector worked, I put it, along with a debug right in the save function only to find something out I didn’t expect. I figured I’d see the debug log every 35 seconds, but instead 35 seconds after game start it began running constantly, which leads me to believe that the save function is happening constantly, also leading me to believe that when GC is being automatically called there’s a massive amount of data that’s bogging down the system. Sure enough, when I removed the save script, the game’s performance never degraded. So, I’m hoping that the issue I have is just WHERE I’m placing my yield command.

#pragma strict
var inventoryScript : Inventory2;
var saveGame : boolean = false;
var loadGame : boolean = false;
var Player2 : GameObject;
// private var
private var playersLastPosition : Vector3;
function Start () 
{
	inventoryScript = GetComponent(Inventory2);
}

function Update () 
{
	if(saveGame == true)
	{
		SaveGame();
	}
	if(loadGame == true)
	{
		LoadGame();
	}
}
function PlayerDied()
{
	PlayerPrefsX.SetBool("IDied", GameObject.Find("Player 2").GetComponent(Playerhealth).iDied);
}
function SaveGame()
{
	for(var x = 1; x>0; x++)
	{
		yield WaitForSeconds(35);
            Debug.Log("Garbage Collect");
            System.GC.Collect();
		PlayerPrefsX.SetIntArray("Ammount in inventory", inventoryScript.ammountInInventoryArray);
		PlayerPrefsX.SetVector3("PlayersPosition", gameObject.transform.position);
		PlayerPrefsX.SetVector3("PlayersRotation", gameObject.transform.eulerAngles);
		PlayerPrefs.SetInt("CurXp", Playerhealth.curXp);
		PlayerPrefs.SetInt("NextScene", GameObject.Find("Player 2").GetComponent(levelvar).LVL);
		PlayerPrefs.SetFloat("slider", GameObject.Find("TOD").GetComponent(TOD).slider);
	    PlayerPrefs.SetInt("MaxXp", Playerhealth.maxXp);
	    PlayerPrefs.SetInt("MaxHealth", Playerhealth.maxHealth);
	    PlayerPrefs.SetInt("CurHealth", Playerhealth.maxHealth);
	    PlayerPrefs.SetInt("Level", Playerhealth.level);
	    PlayerPrefs.SetInt("Money", Playermoney.curMoney);
	    PlayerPrefs.SetInt("Club", WeaponInv.Club);
        PlayerPrefs.SetInt("Sword", WeaponInv.Sword);
        PlayerPrefs.SetInt("Camera", WeaponInv.Camera);
        PlayerPrefs.SetInt("SoulReaver", WeaponInv.SoulReaver);
        PlayerPrefsX.SetBool("weaponready", Player3Weapons.weaponready);
        PlayerPrefsX.SetBool("swordready", Player3Weapons.swordready);
        PlayerPrefsX.SetBool("cameraready", Player3Weapons.cameraready);
        PlayerPrefsX.SetBool("obtainedWeapon02", Player3Weapons.obtainedWeapon02);
        PlayerPrefsX.SetBool("obtainedWeapon03", Player3Weapons.obtainedWeapon03);
        PlayerPrefsX.SetBool("obtainedWeapon04", Player3Weapons.obtainedWeapon04);
        PlayerPrefsX.SetBool("obtainedWeapon05",Player3Weapons.obtainedWeapon05);
        PlayerPrefsX.SetBool("IDied", GameObject.Find("Player 2").GetComponent(Playerhealth).iDied);
	}
}

function LoadGame()
{
	inventoryScript.ammountInInventoryArray = PlayerPrefsX.GetIntArray("Ammount in inventory");
	GameObject.Find("Player 2").GetComponent(levelvar).LVL = PlayerPrefs.GetInt("NextScene");
	gameObject.transform.position = PlayerPrefsX.GetVector3("PlayersPosition");
	gameObject.transform.eulerAngles = PlayerPrefsX.GetVector3("PlayersRotation");
	Playerhealth.curXp = PlayerPrefs.GetInt("CurXp");
    Playerhealth.maxXp = PlayerPrefs.GetInt("MaxXp");
    Playerhealth.maxHealth = PlayerPrefs.GetInt("MaxHealth");
    Playerhealth.curHealth = PlayerPrefs.GetInt("CurHealth");
    Playerhealth.level = PlayerPrefs.GetInt("Level");
    Playerhealth.iDied = PlayerPrefsX.GetBool("IDied");
    Playermoney.curMoney = PlayerPrefs.GetInt("Money");
    WeaponInv.Club = PlayerPrefs.GetInt("Club");
    WeaponInv.Sword = PlayerPrefs.GetInt("Sword");
    WeaponInv.Camera = PlayerPrefs.GetInt("Camera");
    WeaponInv.SoulReaver = PlayerPrefs.GetInt("SoulReaver");
    Player3Weapons.weaponready = PlayerPrefsX.GetBool("weaponready");
    Player3Weapons.swordready = PlayerPrefsX.GetBool("swordready");
    Player3Weapons.cameraready = PlayerPrefsX.GetBool("cameraready");
    Player3Weapons.obtainedWeapon02 = PlayerPrefsX.GetBool("obtainedWeapon02");
    Player3Weapons.obtainedWeapon03 = PlayerPrefsX.GetBool("obtainedWeapon03");
    Player3Weapons.obtainedWeapon04 = PlayerPrefsX.GetBool("obtainedWeapon04");
    Player3Weapons.obtainedWeapon05 = PlayerPrefsX.GetBool("obtainedWeapon05");
	inventoryScript.displayChanged = true;
	if( PlayerPrefs.GetFloat("slider") != 0)
	{
		GameObject.Find("TOD").GetComponent(TOD).slider = PlayerPrefs.GetFloat("slider");
	}
	
	loadGame = false;
}

PS: Yes, I know it’s bad form to call Garbage Collector manually in the vast majority of cases. Was just using for testing purposes.

UPDATE 2

Ok, hello again.

So the long and the short of my issue (described below) is that I have a time of day system in place in my game, and certain groups of NPCs appear at certain times. The NPCs live within empty game objects to keep them organized. It looks something like this:

Morning Group A: 7 NPCs
Morning Group B 7 different NPCs
etc. and so forth.

I have a script that switches the active groups based on the time of day or night:

var TODScript : TOD;
var StartHour : int;
var EndHour : int;
var Trigger : GameObject;

function Update () {
if(StartHour <= TODScript.Hour && EndHour >= TODScript.Hour){
Trigger.active = true;
} 
else{
Trigger.active = false;
}
}

What’s happening though is that while the previous slot’s NPCs are becoming inactive, their animations are not, and over the course of a day (in gametime) they’re eating up memory. So I need to get rid of them. I suppose I could put variables for each NPC in a timeslot and put

var1.animation.Stop();
var2.animation.Stop();

etc.

or even set a boolean:

  var ischaractersetactive : boolean = false;

and check:

if(ischaractersetactive = true){
   var1.animation.Stop();

But that would be ungainly for a couple of reasons:

There are a different number of NPCs in different timeslots.
That same script is used for doors as well, which contain no animation in my game.

So, I’m hoping that maybe there is a universal bit of code that I haven’t found, that just unloads all animations in the scene, stops them, whatever, without having to be tied to the gameobject the animation lives on. Thanks everyone for the continued help. I actually feel like I’ve learned some problem solving working through this issue. God bless.

UPDATE

Based on testing and on comments in this thread, I strongly believe the issue is that my animations aren’t getting unloaded. With the day night cycle in my game NPCs are loaded into time slots of 7 characters each for two hours, then unloaded. (via GameObject.enabled / disabled) This looks like this:

Morning Slot A: 6AM - 8AM (7 animations)
Morning Slot B: 8AM - 10AM (7 animations)
Morning Slot C: 10AM - 12PM (7 animations)

Etc.

In a perfect world, when a slot is deactivated, its animations would be taken out of memory, but using the stats window I see that’s not happening. So in effect what’s going on is the animations are, for lack of a better term, “stacking” in memory, until the evening slot rolls around and there are now 43 animations in memory, even though only 7 or so are currently happening in the scene. So the focus of this now turns to: “is there any way to unload animations from memory?”

Original Post

Hello everyone,

This is a question that probably deserves a “read the docs, jerk,” but I haven’t been able to quite figure out what’s going on.
Have finally gotten my game “finished” in the sense that I have a full game, but can’t quite get performance where I want to. Have tried combining meshes, eliminating updates where possible, reducing mesh colliders, far clip planes, etc. Things seem to work for a bit, but then…

I’ve got an FPS counter on screen for testing purposes. I’ve noticed that at game start, FPS is fine. It’s fine for awhile, in fact. But if I just let the game go, for say 15 minutes, the framerate drops sharply. I can literally do nothing, and the FPS just dies. It doesn’t matter where I’m at, or what’s going on on screen or in game, it just dies. If I continue (in same location and game situation - there’s day time and night time in the game - it’s an RPG) then framerate is back up to good.
Sorry I haven’t provided any scripts or anything as I’m not sure that this issue is script dependent, or just a symptom I’m not doing to optimize the game. Any help / tips are appreciated. Thanks and God bless.

Your assumption about the CPU not being the problem is wrong.

And not likely to have anything to do with CPU or GC at all.

See your PrintScreen again, where it says Main Thread…171.5ms.
That’s a lot of miliseconds my friend.
So, your problem IS on the cpu side.
If it is not the CPU, then look the GPU, if the game crashes, then look for memory.

Interesting what you do with NPC’s and time, to think about really.

Your tris and drawcalls seems fine to me. So, for your edit i see you are on your way to solve it, good luck!

Turns out it was my save system firing off too much, causing Garbage Collector to get bogged down.