J2ME: All classes in one file versus having them separated?

Started by
12 comments, last by MindWipe 19 years, 4 months ago
Well, I just started on my new Job as a J2ME mobile games developer today. And I learned from a colleague that it is allegedly better (read: significantly less memory usage) to have the entire source of your app in one class, with local subclasses (EDIT: inner classes) and so on, opposed to having them in separate files and compile them into separate .class files. Is this true? What are the options? [Edited by - Thygrrr on November 28, 2004 5:00:54 AM]
Advertisement
Well, having a subclass will produce an extra class file (called SomeClass$1.class or something) thus completely missing the attempted saving.
I personally use three classes, none of which have subclasses defined in them. They are: MIDlet, Canvas and Runnable. I sometimes have a second Runnable class if I have the space to do animated loading screens.
Each class does have a JAR/heap space overhead. This is just the way Java works. Obfuscation does reduce this overhead, mainly by reducing symbol names, but there is still plenty of housekeeping information present so reducing the number of classes will save memory. Some obfuscators can merge orthogonal classes together - but this can result in increased heap usage (more data per instance).
However, some J2ME implementations (early Motorola for example) had limits on the code size of a class so this technique can have upper limits.

Skizz
Yeah, Skizz hit the nail, I'll just add some notes:

The extra size per class file ranges between 300 to 500 bytes, I believe. So, this means you should exercise -some- restraint with creating new classes. But often, it's worth spending that 300 to 500 bytes to get nicely organized code. The last Java project I did had 10 different classes.

Also, I've found that code takes up a surprising amount of space. My rough estimate is that every 100 lines of code increases the size of the jar by 600 bytes (this is after obfuscation and after zipping). So by that estimate, if putting some code into a seperate class saves you 100 lines of code, then it's worth it.

EDIT- corrected that estimate I gave.
Wow, thanks for the replys! I still have a question, though:

Quote:Well, having a subclass will produce an extra class file (called SomeClass$1.class or something) thus completely missing the attempted saving.


Speaking of subclass - maybe I used the wrong term, I meant something like this:

class foo{     class sub_foo     {     }}


... is this subclassing? At least that's what I meant.

As for the 500 byte overhead: Lets see. 500 bytes 'on disk' are bad, 500 bytes of extra heap memory lost are actually nothing to worry about, unless the game is fairly complex - and my initial projects won't be complex.

Instead, they'll be simple small apps, e.g. the ubiquitous slide shows, where space matters - cram as many images in as possible - but portability does, as well. Having derived classes so your old code can use your new code will, in my eyes, save you a lot of work and maintenance.
Quote:
Speaking of subclass - maybe I used the wrong term, I meant something like this:
class foo
{
class sub_foo
{
}
}

Yes, that's what I thought you meant and that will create a second class file for the inner class, so it's a bit of a no-no for J2ME.

I wouldn't use inheritance for the same reasons, each derived class requires an extra class file.

As for portability, I use the C preprocessor to optimise the source for each platform:
// <platform.hxx> defines CANVAS as either Canvas or FullCanvas depending on// the platform the application is being built for#include <platform.hxx>public class GameCanvas extends CANVAS{#include <std_graphics.hxx>// other stuff  public void paint (Graphics dc) // ok, I've been using GDI too much  {    // DrawGraphic is defined in <std_graphics.hxx>    // which is optimised for each platform    DrawGraphic (dc, x, y, image_id);   }}


I then use a makefile to build the app:
> make platform=Nokia3650 debug=1 obfuscate=1
which builds the Series 60 debug version with obfuscation. I can also define other stuff as well but I'm sure you get the idea.

Skizz
Quote:Original post by Thygrrr

As for the 500 byte overhead: Lets see. 500 bytes 'on disk' are bad, 500 bytes of extra heap memory lost are actually nothing to worry about, unless the game is fairly complex - and my initial projects won't be complex.


Yeah that's correct, the size of the jar is usually the thing that you have to worry about. A lot of phones, especially the Nokia phones, enforce a 64k jar limit.

Runtime memory is not as bad. Out of the phones that my company supports, the worst one is the Nokia 7210 with 200k of runtime memory. So if your jar is 64k, it's kind of hard to reach that limit. Not impossible though :D
class foo {  class sub_foo {  }}


This is an inner class, and it's a bad idea for J2ME. The compiler adds a *lot* of stuff that you're probably not going to use here, because in Java each sub_foo instance is associated with a containing foo instance, and has access to its members.

If you want the C++ behaviour where sub_foo is just "namespaced within" foo, declare it as static class sub_foo.

Otherwise, your source file organization will have basically no effect on the JAR size, since you're still writing the same classes that do the same things. The exceptions are:

- length of class names matters, since .class files include a lot of that kind of symbolic information. However, any standard optimizer or obfuscator will render that moot.

- packages. Just adding the folder structure to your JAR adds quite a bit of overhead, and then there's the additional overhead of indicating to the code where everything else is located. Just don't do it.

I would say that overall it's better to write things with all the classes that seem appropriate first, and 'draw them together' later. It's a bit of an art, but optimization always is.
You really should keep down the use of classes. In our current project (which is a big project, for a j2me game) we have 4 classes. The MIDlet, Canvas(which is runnable) and two for handling game stuff. It would be possible to skip those two that handles the game stuff and put everything in the canvas/runnable class, but you need to draw the line somewhere to keep things memorywice smart but still have a clean code design.

/MindWipe
"To some its a six-pack, to me it's a support group."
You need to be careful as on some handsets when you hit the 5 class mark there is a noticable lag in the game.

Also try and keep an eye on the amount of threads you have running.

Loads your images as soon as you can! A good place I find is in the constructor of the game canvas class as memory fragmentation is a big problem.

You can get out of memory exceptions when you it seems like there is enough heap left.

If your working with other guys who have been around the block a few times you should be ok. ;)
Okay, this all sounds like sensible advice.

Here's my resolution of what I'll do:

a) first and foremost, produce clean, object oriented code trying to get away with as little iffy stuff (static inner classes, etc) as possible

b) as I suspected, resource strings have the potential to account for several KB of memory (although ascii usually packs quite well). I'll try to use loops and generated resource names and well-structured programming to avoid as much overhead here, while also improving code legibility.

c) I don't think I'll exceed the 5 class limit for a while, mostly, it'll be the MIDlet, the Canvas, and up to one or two game objects.

d) try to get around having to build my projects using JBuilder (which is a clunky process, at best), and work with shell scripts and makefiles to actually package the application. This is particularly useful for the slide show project I've been assigned to, because with tools like Imagemagick, you can pretty much automate the process of resizing/cropping all the images, putting them into various .jars depending on the target platform (e.g. Nokia Series 60, Siemens C 55).

This topic is closed to new replies.

Advertisement