- Home /
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.
Could be the GC cycling? What happens if you run it through the profiler.
Hi Bored$$anonymous$$ormon, Unfortunately as I only have Unity free, I don't have access to the profiler. Did the 30 day trial and at the time this wasn't noticed. (I should add: on Windows / Linux performance degradation isn't noticed. It's only on the Ouya that things get bogged down. Expected that performance would be worse there) Also, sorry for the ignorance, but what does GC cycling refer to? Thanks so much.
Garbage collector. Basically if you destroy a lot of GameObjects and the system needs the memory back it will reclaim memory from objects that have been destroyed. This process is known as garbage collection and is notoriously slow.
Some suggestions to avoid (If this is indeed the problem)
Use object pooling for anything that needs instantiating or destroying on a frequent basis. (Projectiles, generic enemies)
$$anonymous$$anually call the garbage collector at points in the game where performance won't matter. Like when the user pauses the game, or between scenes.
There is an article about the topic here
Click the stats button at the top right of the game view and see how the stats change over time.
@Bored$$anonymous$$ormon: Unfortunately, unless I'm doing it wrong (and I could be) it seems Garbage Collector isn't my culprit. I added the following to a dontdestroy GameObject in the intial scene:
function Start() {
var tmp = new System.Object[1024];
// make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks
for (var i : int = 0; i < 1024; i++)
tmp[i] = new byte[1024];
// release reference
tmp = null;
}
and then this at each pause:
if(OuyaSD$$anonymous$$.OuyaInput.GetButtonDown(0, OuyaController.BUTTON_A) && gamePlay == true)
{
Close$$anonymous$$enus();
while(check < inventoryArray.Length)
{
inventoryArray[check].active = true;
check++;
inventory = true;
gamePlay = false;
Pause(false);
System.GC.Collect();
Enemies.active = false;
NPCs.active = false;
to no effectual change. Set my Pixel Error up on terrain, texture sizes down, disabled NPCs whenever entering buildings, and... nothing. Each day, at 7P$$anonymous$$ sharp the game bogs down if played continuously. When I stopped the game, and hit continue, the lag is gone. Ugh, so frustrating.
Answer by Conect11 · Aug 21, 2014 at 02:24 AM
Turns out it was my save system firing off too much, causing Garbage Collector to get bogged down.
Nice work. Guess I should go with my hunches more often.
Incidentally it does seem to be a acceptable practice in games to manually call the GC. Check out the memory management article
ah, but there's a catch. Sigh, there always is. It never can be easy.
$$anonymous$$anaged to fix the issue, but in doing so, created a new problem: Continue option never works now. :(
Answer by DBar · Aug 19, 2014 at 05:18 AM
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!
ok, so at this point I've been doing some more experimenting, and am wondering if loading and unloading resources might be a way to get these things out of memory.
Your answer
Follow this Question
Related Questions
Multiple animation with single button 1 Answer
I Trying to Make a Game for my OUYA 0 Answers
AI Animation problems 1 Answer
Android game too heavy after installation! 0 Answers
Press GUI Button and make it play animation on Android 1 Answer