One thing I do to limit this is limiting the use of dynamic variables. My games typically have no more than four class files and all my data is stored in arrays. I know it's arcane, but it does relieve a lot of these problems on underpowered phones.
The classes on my last game were: Main (which included a network thread), Data, Canvas (which included an animation/tick thread), and Menu. I have my own custom menu system because the List class requires a new instance for every menu. I like having one instance and repopulating it and it uses arrays internally.
I have some instances where I have to use strings, I try to limit them as much as possible. I try to keep most strings static final, but there is always the case where you need to concatinate two strings and I typically don't use +, I create a new StringBuffer, just so I know exactly what is happening, not relying on a translation. That's typically the only dynamic allocation I allow in my games. Everything else is locked down up front.
im doing porting for about 25 phones so code splitting has already happened (though i really, really hate it)
This is actually the worst possible development scenario I could possibly imagine and I hate it too. I don't think Sun really cares though? Conditional compilation (#ifdef) would tend to make life much much easier, but that seems to be taboo to even mention. Sort of like saying the Emperor isn't wearing any cloths and Java is so portable that conditional compiliation has no place in such a perfect system. That said, I'm sure I could build some sort of Ant system to preprocess the conditional stuff for me, but as I've said in earlier posts, I'm lazy and that sort of Ant system would require a ton of work. Especially to get it front ended on WTK which I use for my final builds. Just the thought hurts my brain.
I noticed recently that NetBeans has some sort of code splitting management system to make this easier. Seemed like a sledgehammer to drive a carpet nail that conditional compilation would easily solve.