Game Development Community

EXC_BAD_ACCESS crash, tried everything.

by Peter H · in iTorque 2D · 11/05/2009 (12:50 am) · 14 replies

I'm trying to test my game on a device but it crashes after loading a level for the second time.

I'm running OS X 10.6
iPhone SDK 3.12
Device: iPhone 3GS 16Gb


- I've compiled TGBGame with PUAP_OPTIMIZE and PUAP_SCRIPT_CHANGE flags.

- I'm building my game for iPhone SDK 2.2.1 in TorqueGameBuilder with FULL optimization

- I compile my game using the iTGB_SCRIPT_OPTIMIZE target (which has both optimization flags in place)

- The game starts OK even though it takes up to 20 seconds to load.

- My game is broken down so that the menu system lives on one level and the game portion on another level.

- The crash happen when returning to the menu level after playing the first game level.

- The endLevel/loadLevel commands are fired when you click "Return to Main Menu". I read that this can cause a crash without a schedule delay, so I added this too.

Any ideas??? Thanks.


#1
11/05/2009 (2:36 am)
Have you compiled with the exact same preprocessor settings in your OSX build as well as your iPhone build, and built all of your DSOs with the OSX version? That is the most common cause of this error - a preprocessor mixup. Also, what does the crash report from your iPhone say? That should show much more of what the problem could be.

I got the EXC_BAD_ACCESS error numerous times before working out the proper ways for developing on the iPhone. There are a lot of things that can cause this, and I would be more than happy to help you work out the cause on your end. :)
#2
11/05/2009 (2:51 am)
In the Xcode (Mac OS) project, I compiled the TGBGame target with the same preprocessor flags as the iTGB_SCRIPT_OPTIMIZE target in the Xcode_iPhone project.

When you say "build all DSOs with the OSX version", doesn't this happen when you build the game from TorqueGameBuilder?

I'm not on my development machine at the moment so I can't look at the crash report.
#3
11/05/2009 (2:55 am)
When you run the game from TorqueGameBuilder, it will build the DSOs using the TGBGame that is currently compiled for use when running a game through TorqueGameBuilder. However, if you are using different preprocessor definitions with that TGBGame than your iTGB_Script_Optimize target, then you'll get lots of EXC_BAD_ACCESS errors.

You'll also receive that error / crash a lot if you are eating up too much of the iPhone's memory, so make sure you are being very careful to load only your needed data only when you need it.
#4
11/05/2009 (3:11 am)
I'm compiling TGBGame with these options:

__MACOSX__
TORQUE_DISABLE_MEMORY_MANAGER
TORQUE_PLAYER
USE_COMPONENTS
PUAP_OPTIMIZE
PUAP_SCRIPT_CHANGE

I'm compiling iTGB_SCRIPT_OPTIMIZE with these options:

__IPHONE__
TORQUE_DISABLE_MEMORY_MANAGER
TORQUE_PLAYER
USE_COMPONENTS
PUAP_OPTIMIZE
PUAP_SCRIPT_CHANGE

Do I need to compile the TorqueGameBuilder target with the same flags?
#5
11/05/2009 (3:15 am)
Could the crash I'm experiencing be related to the issue you had here: http://www.garagegames.com/community/forums/viewthread/96727
#6
11/05/2009 (3:19 am)
Ok. So it's not your pre-processor definitions.

The reason for my crashes there were primarily 2 reasons - my preprocessor definitions did not match, and I was trying to load way too much into the iPhone's tiny memory space at once. By fixing my definitions and writing a custom resource management system, I now experience 0 crashes with iTGB 1.2 and iTGB 1.3, and get a pretty high framerate (around 30fps+).

When you start your game, are you making sure that you are loading as little as possible? As in - if it's not needed, it does not get loaded? Same with GUI screens. Exec them when you need them, delete them when you're done. Same mantra for _EVERYTHING_ in the game.

Remember, the iPhone is not a computer - it's a mobile device that is, in all reality, very slow and has very little memory. There is a lot you can do with it, but you can't treat its memory like you would on a PC, Mac or regular game console. :)
#7
11/05/2009 (3:28 am)
Man it sounds like you've been through hell with this stuff. I appreciate your help.

Maybe I'm loading too much at the beginning, I will try loading stuff as needed.

How do I unload data when I don't need it? I'm using endLevel() to unload my levels, is this what you mean?

By the way, does TorqueGameBuilder (The editor tool) need to be compiled with the same flags as TGBGame and iTGB_SCRIPT_OPTIMIZE?
#8
11/05/2009 (3:37 am)
I've been through hell and back, yes, but as a result I've learned a LOT about how the iPhone works, and through that learned how any game engine would function with it. The reason I love iTGB is because it keeps everything flat out and open for you, so you can do what you want. But, with great power comes... well, you know the line. :)

First off, if you are relying on any behaviors in your game, I would avoid using the level loading functions. Instead, load one level then populate and delete objects as needed to build your levels. The reason for this is that it is very easy to make level loading crash if objects that depend on other objects get loaded in the wrong order. A custom resource loader can easily fix this, however.

As for resources... no, I don't mean endLevel();. Let's say when you start the game, you have a logos sequence. So you should exec ONLY ONE line when you start the game:

exec("./gui/myLogosSequence.gui");

You show the logos. Great. Now when you're done, we exec the title screen, then push the GUI for it. We no longer need to logos sequence. So delete it from memory by doing this:

myLogosSequenceGui.delete();

Now the memory it was using has been freed for other objects to take its place.

Now at the same time (I know nothing about your game, so I'm gonna generalize here)... say you have a boss battle in your level. Do you need the assets for that boss graphic throughout the level? Probably not. At the same time, do you need the assets for enemies in the level during the boss battle? Also probably not! So before getting to the boss battle, first delete your imagemap datablocks used for the enemies by doing...

enemyImagemapDatablock.delete();

Now it has been removed from memory - but of course make sure you have a quick watcher function in place to not delete the datablocks until you have done a .safeDelete(); on all the objects that depend on it.

Now, I would recommend having some sort of a sequence to display while you are loading the boss assets in the background - unless your boss assets all use the .PVR graphics format, then you don't need to worry about it. The reason here is the all graphics formats will need to load and uncompress into the iPhone's memory, which can cause a short pause / delay in your game, so you should cover that up with a fade out or a dialog screen or something. But a PVR is not compressed, so it will load with 0 delay time.

Finally... as for TorqueGameBuilder having the same flags... that's an interesting one. I haven't played with that too much yet, but here is the fun part - if you save our a .t2d level from it, or a .eff or anything of the sort, then they will need the same preprocessor flags as everything else. So, technically, yes, it should be compiled with the same flags. But, again, you probably want to avoid using the .t2d level files directly (at my company, we build the levels in the TGB editor, then copy/paste the .t2d contents into a custom level format so our resource loader can handle the loading and unloading of it).
#9
11/05/2009 (3:51 am)
OK, I think this will get me headed in the right direction.

Instead of using behaviors, I've created classes to manage/control my game objects. Maybe there are some inter-dependencies that I'm missing. If so, I can probably move everything into one level and go from there.

Thanks for explaining the load/unload stuff.. this is very helpful.

I will take another crack at this tomorrow and let you know how it goes.

Thanks again for your help.
#10
11/05/2009 (3:55 am)
Classes should help you to avoid the object interdependency issues of behaviors. The problem technically is that objects don't always load in the same order that you saved them in - so if A depends on B and B isn't loaded yet, or the behavior for B isn't loaded yet, then A could end up causing a crash. Incredibly solid code with proper try/catch conditions on the C++ end, checking to make sure things exist before using and all of that can help a lot, but also adds a lot more work into your development time, so it really depends on how much time you can devote.

But the classes should manage everything just fine, so before you rip everything out of the t2d levels, I'd first do a very solid overview of what you have in memory at what points in time, and see if it's too much or not.

Also, make sure all your graphics are power of 2 in size, or you'll be using more memory than you need. AND... keep in mind, your screen is only 320x480 and vice-versa, so if you're loading frames larger than that, you're just wasting space. :)
#11
11/07/2009 (11:15 pm)
F*ck Yeah! I finally figured this out!

It turns out that this was a dependency problem like you mentioned Dave.

If you bind the joystick to an object, you have to unbind it before unloading or deleting that object. Otherwise the actionMap will continue to receive events from the joystick and pass them to an object that no longer exists. Seems pretty obvious now that I think about it.

This is the code I was using to bind the joystick to my player:

moveMap.bindObj(joystick0, xaxis, "joystickMoveX" , player);
  moveMap.bindObj(joystick0, yaxis, "joystickMoveY" , player);


Now before I unload my level, I unbind the joystick from the player like so:

moveMap.unbindObj(joystick0, xaxis, player);
  moveMap.unbindObj(joystick0, yaxis, player);

This solved the crash!
#12
11/07/2009 (11:17 pm)
I have a feeling that other people may be running into this problem... I hope this solves your crash!!
#13
11/07/2009 (11:19 pm)
Oh yea - that would nuke it for sure! And I can see how that could be a tricky one to catch. I'm glad you caught it, Peter! Please feel free to email me or msg me here on the forums if you have any other problems - I'd be glad to help!
#14
11/08/2009 (1:22 pm)
Oh man, that's a weird one. Sure, it's logical. But shouldn't there be some protection against that in the engine? Stick this in a tip thread somewhere :)