Hey Folks! Memleak work continues today, as conditions get wrapped-up, and we turn to encounters.
For conditions, I finally found out where the extra camp conditions in memory were coming from. AI was cloning hex campsite conditions each time they visited, and never releasing them. As a result, they just piled-up in memory, and for long games with lots of creatures, this could add-up to significant memory. The fix was to just not clone them, as the camp condition should theoretically be the same for all camp visitors. (There is a special case in the code not to destroy a campsite condition when a creature removes it from itself.)
There was also, coincidentally, a bug fix in the way creatures were destroyed. A typo was causing camps and ground to be destroyed when a creature got destroyed, so I've fixed that.
In brief tests, that seemed to solve the remaining condition memory leaks, and cause no other issues. So we'll go with that for now. It's always possible small changes like this have unforeseen effects, though.
Moving on, Encounters are the next big one. After some investigation, it appears each turn, for each creature in an encounter, encounters are getting cloned like crazy. Like 150 encounters in memory after 1-2 turns into the game. (Which are, ostensibly, from either the player or Yezinka.)
When you factor in combat and scavenging (which are also encounters, and in combat's case, involve multiple creatures), this can really get out of hand.
My first idea was to just change the way encounters get requested in the data handler. It's cloned at the source, likely to avoid collisions, and since encounters shouldn't change much from creature-to-creature, I figured it couldn't hurt to not clone them.
But then I remembered Tiago's struggle to get loaded encounters to fit into memory. That's why we load each on-demand from disk.
Plus, battles and scavenge encounters get customized per instance, so that wouldn't work for them the minute more than one creature needed it simultaneously.
So my next idea was to destroy them when the creature is done with them. This turns out to be way harder than expected. Even as the code's author, I can't find a safe (and still reliable) place to do this. Either I delete it too early, or miss my chance before it disappears into memory.
Enter the processed encounter queue. I'm going to see if I can store a reference to each encounter that a creature experiences in a list. And after "some time," that list gets its oldest members destroyed and removed. This way, there's kind of a running destroy queue for each creature. And to avoid figuring out the soonest possible "some time," I just chose 2 turns. In theory, an encounter from two turns ago should be safe to destroy. And when the creature goes bye-bye, the remaining 2 can, too.
I think this approach is sound, if a bit hacky.
The trouble is, it doesn't work. At least, not appreciably. It might've reduced the number of encounters orphaned by the number of encounters creatures have collectively experienced. But for 1-2 turns into the game, this is like 2-5 encounters from a list of ~150. Not good enough.
I have a hunch, though. This may just be the first step. The next step might be to check when each encounter presents its options/choices for the next turn. I bet each outcome is cloning an encounter, and these are just being forgotten each turn. I'll look into those tomorrow.
Whew! Quite a day! And I'm still feeling pretty sick. Almost worse, in fact. Double-whammy? Undead disease? God, I just hope it goes away soon. I'm done with this cough/nose/chills/aches shebang.