Choosatron: Crushing the Final Bug

July 12, 2012

Last night I finished the final feature that would allow full story play support for the file structure I created. Auto-jump, which simply allows you to set a single, unlabeled choice on a passage so it will be printed out and immediately forward to the link provided and continue from there. This is useful when you want to converge two different paths back together with different narrative preambles but common narrative body and the same choices. Is that confusing?

Path 1: “…After singing along to the radio with your friend for hours, the cabin is finally in sight.”

Path 2: “…you awaken from the bizarre dream, your friend pointing ahead to the cabin up ahead.”

/

“The gravel crunches under the tires as you park. It really is a beautiful cabin you think to yourself. Should be a great weekend.”

See what I mean? So with this in place I was able to play through, but suddenly…it stopped. Noooo! I happened to have a log statement outputting free kilobytes of memory before each passage is output, and it was heading steadily downward.
968…906…842…780…724…662…death.
No question, a nice juicy memory leak. A very consistent one losing about 62kb per passage. I walked through my code carefully, making sure that each path and passage element is correctly freed. Then I started commenting items out to keep the case as simple as possible. No change whatsoever. Only change was the memory leak was slightly less the more data I loaded in each chunk of the passages.
Choosatron Proto Bits
Interesting…that means the fewer file.open() calls I make, the less memory is leaked despite loading the same number of bytes. At this point I did what any decent programmer would do: pick the best keywords for what I understand about my problem thus far, and google it. This, my friend, was a situation where something could have easily taken days to fix, but I noticed enough clues to find a problem I was not alone in. I immediately found an issue filed here: Arduino Issue 814. The gist is simple:

When a file is opened a malloc() is performed to get memory. When a file is closed the memory is freed. If the file object is destroyed before the file is closed, the memory is never freed.

File::~File(void) {
close(); // <-- The FIX???
// Serial.print("Deleted file object");
}

I tossed in the one line ‘fix’ to confirm my files weren’t getting closed properly. I added it to the library, recompiled, uploaded, ran…968…947…947…947…947…and this continued to the end. Then I played again. Then I continued. NO LEAKS. This is one of the most incredible feelings in the world, especially when memory management is allll up to you. I’m using the Micro SD card as my memory (essentially) so not leaking it all over the place when I use it is a plus. Of course, this isn’t really the fix, as managing your open files is up to YOU. I removed the one-liner, and searched through my code to ensure that every file I opened was also closed after use. Once again, I confirmed no leaks, and fixed it the right way!

The Choosatron Deluxe Adventure Matrix™ software is working! It’s not done, but this is where it gets really fun. Getting people to write content for it, demoing it, and of course polishing the code and adding more features for authors to play with. Next step is setting up the power regulator, power input, and power button so I can take the experiment where the people are. Hopefully I’ll have it with me at CONvergence a couple days from now for some geeky attention.

LET'S WORK TOGETHER!