You Are Here:

Community: Wiki

This page was last modified 10:49, 5 June 2009.

How to optimize in Java ME

From Forum Nokia Wiki

There are three key factors to considered when you want to optimize your Java ME applications

  • Performance
  • Size

You should delay optimization until the last minute, after you create the main features of our application, but you need to keep in mind all the key factors throughout the development cycle to avoid huge changes at the end.

Contents

Performance

Rule number one for performance is "keep it simple", don't try to create over complex systems, for your mobile phone, remember people want fast and easy to use applications/games, to use on the move. With this mind take in account the following issues:

Threads

  • Use only one application thread, avoid multiple threads. Many devices cannot handle too many threads, they simple stop. Network thread is the only exception for creating a new thread
  • Minimized usage of synchronized, is expensive on legacy devices and is very common to create poorly synchronized code. Synchronizing run with paint() and keyPressed() is ok.
  • Avoid using Timer class, an extra thread is created for each one.
  • Create a background thread in startApp() and reuse it.
  • Don’t use Display.callSerially(), is very slow and buggy on many devices. A new thread is created in most implementations
  • Avoid serviceRepaints() on legacy devices when performance become an issue
  • Might need to ensure thread safety (background thread and system thread) if serviceRepaints() is not used
 An example for the base structure for you application:
public void startApp() {
  animationThread = new Thread(this);
}
 
public void run() {
  init();
  while(!exitApp) {
    updateModel(); // your app logic
    repaint();
    serviceRepaint();
    sleep(50); // may choke slow devices if too small
  }
}

System Callbacks

You must handle with care the system callbacks, they are called by the system thread. They must not block and should return as soon as possible to avoid slowing down the VM. A crash can happen if not returning quick enough. Here is a list with the more common system callbacks:

  * paint
  * keyPressed
  * startApp/pauseApp
  * hideNotify/showNotify
  * MIDlet constructor  


Below you have a bad example of a system callback:

public void paint(Graphics g) {
  updateModel();
  drawBackground(g);
  drawForeground(g);
}
 
public void run() {
  while(!exitApp) {
    repaint();
    serviceRepaints();
    sleep(50);
  }
}

As you may have noticed we are updating our model, an expensive operation, during the system event paint. We should change our code to the following:

public void paint(Graphics g) {
  drawBackground(g);
  drawForeground(g);
}
 
public void run() {
  while(!exitApp) {
    updateModel(); // better do it here
    repaint();
    serviceRepaints();
    sleep(50);
  }
}

Different Devices - Different Performances

There are huge differences between high end and low end devices, devices can be much faster or slower than you expected, so you cannot assume performance.

If you have your game logic based on frame rate this may result in totally unplayable game. You should instead base your game on actual time instead, like the example below:

public void updateModel() {
  curTime = System.currentTimeMillis();
  elapsedTime = curTime – prevTime;
  // using elapsedTime for your app logic here
  prevTime = curTime;
}
 
public void run() {
  while(!exitApp) {
    updateModel();
    repaint();
    serviceRepaints();
    sleep(50);
  }
}

Another thing to take in account is the performance of some APIs, some calls are slower than others:


  • drawString(), replace with graphics font
  • drawArc(), Vector, Hashtable, replace with own implementation
  • drawImage(), replace large images with a series of smaller images for some devices


Another thing to handle with care is collision detection, it must be calculated in between frames to avoid problems on low frame rate devices.

Disable certain features on slow device via JAD entry. E.g. if "tree.png" does not exist, don't draw the tree sprite

I/O

The use of RMS and getResourceAsStream calls is very slow. Take the following consideration when using them:

RMS

  • Read entire record into a buffer
  • Then parse the buffer
  • Similarly, write to a single buffer, then write the buffer to a record

getResourceAsStream()

  • Extremely slow on some devices (as slow as 20 bytes per second)
  • Class loading is much faster on these devices
  • Workaround—store data in separate class files instead of using resource. This may result in slightly longer application load time

General

Here some “Little things” that make big differences:

  • Avoid unnecessary object creation/memory allocation.
  • Reduce, reuse, recycle the object instances you use
  • Strings, don't do big string concatenations using "+", use StringBuffer class instead
  • Image, small is good—split large images, create a Image cache
  • Object pooling might work in some cases
  • Loops, avoid unecessary creation/disposal of variables inside loops
  • Use switch-case instead of if-blocks, they are translated to faster java bytecodes
  • Use public variables directly instead of using get/set methods.
  • Set variables to null when you don't need them anymore
  • Garbage Collector, call frequently and explicitly on some devices. Beware of non-compacting GC
  • Use local variables instead of global variables when you can. Local variables are faster and use less bytecode

Take a look at the following example:

for(y = 0; y < oriHeight; y++) {
  for(x = 0; x < oriWidth / 2; x++) {
    int idx1 = y * oriWidth + x;
    int idx2 = (y + 1) * oriWidth – 1 - x;
    curPixel = buf[idx1];
    buf[idx1] = buf[idx2];
    buf[idx2] = curPixel;
  }
}

If we do the index creation outside of the loops like this:

int idx1;
  int idx2;
  for(y = 0; y < oriHeight; y++) {
    idx1 = y * oriWidth;
    idx2 = (y + 1) * oriWidth – 1;
    for(x = 0; x < oriWidth / 2; x++) {
      curPixel = buf[idx1];
      buf[idx1] = buf[idx2];
      buf[idx2] = curPixel;
      idx1++;
      idx2--;
    }
  }

It can save a few seconds on a real device!

Size

The size restriction for Java ME applications comes from two sources:

  • Device capability, some devices only accept 64 kb applications!!
  • Operator’s gateway limitation, to avoid customers waiting too long (and pay to much)for an application to download some operators limit the max application size (normally around 300kb)


Device JAR size limit has improved continuously over time, but it is never enough for developers! So here some tips to help you

  • Minimize classes number, avoid OOP (if practical), each class/interface contribute at least 250 bytes of overhead after compression. Can get away with 2 classes: one MIDlet class and one Canvas class.
  • Use an Obfuscator
  • Optimize Images
  • Change ZIP algorithm, JDK’s JAR utility is not optimal. Use open source, freeware or commercial alternatives, where number of passes are configurable, but beware of device compatibility.

Obfuscator

What does it do? It's original purpose is to make reverse engineering very difficult by:

  • Eliminate packages (i.e. always use default package)
  • Rename method/field names
  • Remove unused code

But is has the nice side effect of creating smaller class files size (and also slightly faster). Some of them also perform bytecode optimization. They can typically can reduce file size by 30–50% There are very good Open source obfuscators (Proguard, Retroguard) and many other commercial products.

Images

What are the problems?

  • Not compressible
  • Each PNG file contains more of less the same header and footer
  • Flipped images, transformed images on MIDP 2.0 devices are either very slow or not working. Isn't supported in MIDP 1.0 devices. Must include flipped version of sprites at build time this can double or quadruple the size

Here are the solutions:

  • Use PNG optimizer like OptiPNG or PNGCRUSH
  • Alternatively, do not compress image content - larger PNG sizes before compression but smaller at the end
  • Combine multiple PNGs into a single resource bundle or a large image. It becomes more compressible and we stripped off the header and footer
  • Flipped images
  • Dynamically flip images at run time
  • Potentially a performance/JAR size tradeoff
  • Reduce colour depth (if possible)

See How to optimize PNGs to reduce JAR size

Rate This

 
Bookmark this page: DeliciousDiggFacebookGoogleYahooStumbleUponRedditFurlTechnocratiMagnoliaTwitter  Share this page Share this page Print this Page Print this page Invite a friend Invite a friend
Email Newsletters Press Terms & Conditions Privacy Policy Sitemap Contact Us © 2009 Nokia 
RDF Facets: qdcZdescriptionQSxEa0E20WikiE20javaE20symbianE5fosE20s60E20maemoE20cE2bE2bE20WikiE20HomeE20WikiE20HelpE20OverviewE20GlossaryE20CreateE20PageE20ProposeE20anE20ArticleE20SpotlightE20TopicE20E2dE20WE52TE20WidgetsE20ProgrammingE20E4canguageE20E2dE20SymbianE20CE2bE2bE20E2dE20OpenE20CE2fCE2bE2bE20E2dE20JavaE20E2dE20FlashE20E4citeE20E2dE20PythonE20WebE20TechnologiesE20E2dE20WE52TE20WidgetsE20E2dE20WidSetsE20ToolsE20andE20SE44KE20CodeE20E45E78amplesE20KnowledgeE20BaseE20TechnologyE20AreasE20SoftwareE20PlatformsE20E44evelopmentE20ProcessE20E3fE3fWikiE20ChineseE20E3fE3fE3fWikiE20JapaneseE20PortugueseE2fBrazilianE20E52ussianE20WhatE20linksE20hereE20UploadE20fileE20SpecialE20pagesE20PrintableE20versionE44ownloadE20asE20PE44FE20GoE20ToE20E2eE2eE2eX qdcZidentifierQSxhttpE3aE2fE2fwikiE2eforumE2enokiaE2ecomE2findeE78E2ephpE2fMMPE5ffileX qdcZpublisherQUxhttpE3aE2fE2fswE2enokiaE2ecomE2fidE2fc764fd1cE2d8b06E2d499aE2d9a6aE2d17c3903d5a65E2fforumE5fnokiaE5fcrawlerE5fagentX qdcZtitleQSxMMPE20fileE20E2dE20ForumE20NokiaE20WikiX qdcZtypeQUqfnZE45E78cludedFromGeneralE4cistingsQ qdcZtypeQUqfnTypeZCommunityContentQ qdcZtypeQUqfnTypeZE52esourceQ qdcZtypeQUqfnTypeZWebpageQ qdcZtypeQUqfnTypeZWikiContentQ qdcZtypeQUqmarsZManagedE52esourceQ qdcZtypeQUqwebZInformationE52esourceQ qdcZtypeQUqwebZPageQ qdcZtypeQUqwebZE52esourceQ qdcZtypeQUqrdfsZE52esourceQ qrssZdescriptionQSxEa0E20WikiE20javaE20symbianE5fosE20s60E20maemoE20cE2bE2bE20WikiE20HomeE20WikiE20HelpE20OverviewE20GlossaryE20CreateE20PageE20ProposeE20anE20ArticleE20SpotlightE20TopicE20E2dE20WE52TE20WidgetsE20ProgrammingE20E4canguageE20E2dE20SymbianE20CE2bE2bE20E2dE20OpenE20CE2fCE2bE2bE20E2dE20JavaE20E2dE20FlashE20E4citeE20E2dE20PythonE20WebE20TechnologiesE20E2dE20WE52TE20WidgetsE20E2dE20WidSetsE20ToolsE20andE20SE44KE20CodeE20E45E78amplesE20KnowledgeE20BaseE20TechnologyE20AreasE20SoftwareE20PlatformsE20E44evelopmentE20ProcessE20E3fE3fWikiE20ChineseE20E3fE3fE3fWikiE20JapaneseE20PortugueseE2fBrazilianE20E52ussianE20WhatE20linksE20hereE20UploadE20fileE20SpecialE20pagesE20PrintableE20versionE44ownloadE20asE20PE44FE20GoE20ToE20E2eE2eE2eX qfnZdistributionQUxhttpE3aE2fE2fwikiE2eforumE2enokiaE2ecomE2fX qfnZtypeQUqfnTypeZCommunityContentQ qfnZtypeQUqfnTypeZE52esourceQ qfnZtypeQUqfnTypeZWebpageQ qfnZtypeQUqfnTypeZWikiContentQ qfnZupdatedQDx2008E2d10E2d02X qfnZuserE5ftagQSxfileX qfnZuserE5ftagQSxlibpathX qfnZuserE5ftagQSxmmpX qfnZuserE5ftagQSxresourceX qmarsZdescriptionQSxEa0E20WikiE20javaE20symbianE5fosE20s60E20maemoE20cE2bE2bE20WikiE20HomeE20WikiE20HelpE20OverviewE20GlossaryE20CreateE20PageE20ProposeE20anE20ArticleE20SpotlightE20TopicE20E2dE20WE52TE20WidgetsE20ProgrammingE20E4canguageE20E2dE20SymbianE20CE2bE2bE20E2dE20OpenE20CE2fCE2bE2bE20E2dE20JavaE20E2dE20FlashE20E4citeE20E2dE20PythonE20WebE20TechnologiesE20E2dE20WE52TE20WidgetsE20E2dE20WidSetsE20ToolsE20andE20SE44KE20CodeE20E45E78amplesE20KnowledgeE20BaseE20TechnologyE20AreasE20SoftwareE20PlatformsE20E44evelopmentE20ProcessE20E3fE3fWikiE20ChineseE20E3fE3fE3fWikiE20JapaneseE20PortugueseE2fBrazilianE20E52ussianE20WhatE20linksE20hereE20UploadE20fileE20SpecialE20pagesE20PrintableE20versionE44ownloadE20asE20PE44FE20GoE20ToE20E2eE2eE2eX qmarsZlanguageQUxhttpE3aE2fE2fswE2enokiaE2ecomE2flanguageE2d1E2fenX qrdfZtypeQUqfnZE45E78cludedFromGeneralE4cistingsQ qrdfZtypeQUqfnTypeZCommunityContentQ qrdfZtypeQUqfnTypeZE52esourceQ qrdfZtypeQUqfnTypeZWebpageQ qrdfZtypeQUqfnTypeZWikiContentQ qrdfZtypeQUqmarsZManagedE52esourceQ qrdfZtypeQUqwebZInformationE52esourceQ qrdfZtypeQUqwebZPageQ qrdfZtypeQUqwebZE52esourceQ qrdfZtypeQUqrdfsZE52esourceQ