CSDN博客

img sunyuzhe114

如何使midlet提速

发表于2003/2/11 14:00:00  938人阅读

1 非常general的,适用于所有java程序:少用字符串连接,多用StringBuffer
2 尽量用固定大小的数组代替使用Vector
3 如果可以不使用新class就能实现功能,就不要增加新的class,因为每个class都有一定的内存开销
4 使用有限的面向对象,因为纯粹的OO往往意味着更多的虚方法,更多的层次关系,更多的class
5 考虑使用public域(即数据成员)代替getter和setter
6 对确定不必被继承的方法使用final修饰符
7 使用BufferedInputStream或BufferedReader来包裹输入流
8 发行之前使用混淆器处理你的classes,除了能防止别人任意反编译偷窥你的程序,也能减小class文件的尺寸,因为混淆器往往用较短的字符串代替原来的变量或方法名。
——rocks
************************
* 人は遊び存在である。 *
* To Play is Human.  *
************************

转载自www.cnjm.net

如果有可能的话,考虑用西门子提供的一些库,如GAME、MMC等,能显著提高速度,但代价是兼容性不好。 

——asmair


我的原则是有这么其中两个:
1。对于哪些需要动态的复杂算法才能达成的目标,能否在pc机器上就预先处理一下,而形成静态的数据结构,然后再用简单算法来使用。
2。要重视的是:反复频繁的操作是性能的一个瓶颈。在这上面下功夫非常值得。比如:
某个循环一次操作只需耗费 10ms, 如果你一个不注意,让它耗费了 20ms (这时你可能不觉得有问题,才多了小小的 10ms嘛)。再假设这个循环很频繁,占软件运行总时间的 30%,那么,这样就会在不经意间严重降低了总体速度。
所以解决方案首先就是去查软件的性能瓶颈,再对症下药。

—— leelong

用Borland Optimizeit Suit Enterprise优化一下更好,请问各位有没有她的注册码呀,Borland给我的试用license到期了,不能用啦,也找过几个破解的东西,全都名不符实,火页!有注册码的请举手!!

——zmg229


我也有两个问题:
1、用对象来封装数据会不会明显地影响速度,比如说在输入输出的时候使用包含多种不同类型属性的对象,而不是原始的整数等。
2、显示调用System.gc()是不是可以明显加快程序运行速度。

—— Fuchs

1.不是很明显的吧,但肯定是有影响,要分情况处理,主要解决显著影响性能的地方,细节上的优化应该是最后做的事情
2.应该是会降低运行速度,不过可以优化内存使用情况

——rocks

to rocks:
1.对于你的第三条:用inner class实现的话会增加内存开销吗?
2.对于你的第五条:因为我们做的是手机的程序,安全是第一的,所以我建议你把第五条去掉!
——anonimousboy:


to anonimousboy:
1 inner class编译后就会生成一个单独的class文件,形如MyHostClass$MyInnerClass.class这样的,即使是匿名内嵌类也一样。
2 想象不出来public field会对安全性有何影响,呵呵,getter和setter的首要目的是增强对象的封装性,而并非考虑安全性。
3 如果真的安全性和性能发生抵触,那么就要根据具体问题来具体分析了,如果做的是证券软件,毫无疑问安全性是最重要的,如果是个即时的动作游戏的话,那性能应该是首要考虑的问题。
Just For Your Infomation
:)
——rocks

我刚学j2me没多久,以下几点是根据我对java语言特性的一些浅见来谈的,大侠们多指教
A:对于处理器速度慢的问题:
尽量使用数组,少用Vectors等对象,即使要用也要按其真实预期大小指定初始空间,其实手机上的程序都不大,通常我们完全可以把一些细节考虑通透,预先做好设想
B:对于内存少的问题:
1.有时候要牺牲一些面向对象的特征,用尽量少的类来实现程序
2.用尽量少的方法实现功能,那样做应该会花费很多空间在堆栈上
3.留点神,使用合适的数据类型,不要象在台式机上那样大大咧咧的,既然穷就要勤 俭持家啊,好习惯是最重要的,而且要尽可能少用对象,多用基本类型
4.该放手时就放手,丢个null给对象,不用倚赖GC(你以为养个GC不用钱啊?),不要让GC太忙啊
5.……等我想好了再……

—— yuanaoe

同意1,
不同意2,其实函数堆栈并不浪费时间。功能独立是最重要的,方法少可能会带来更多的代码浪费。
同意3,每个空类有200字节的空间。
不同意4,你给null了只是消除了它的连接,对象并不释放,还是要等GC,但是如果调用GC,无论它是不是null,只要它不再使用,就会释放掉。

——horsethief


赋予null,跟不赋予null收集起来的效率是一样的吗?而且cldc中实现的gc跟j2se中的gc比较,无论是效率还是安全性都大打折扣

——yuanaoe


不要用混淆器,它有可能导致程序不能正确运行。提速是最关键的,而尺寸不是大问题,因为存储器的大小的发展速度很快。

——bobyyuan

我谈一点自己的体会。如果必须使用多线程的话,尽量减少线程切换的次数,这样可以明显提高程序速度。方法如下:
class MyThread extends Thread{
...
public void run(){
  while(true){
    setPriority(Thread.MAX_PRIORITY - 1);
    ...
    ...
    ...
    setPriority(Thread.MIN_PRIORITY);
  }
}
}

——Fuchs

—— jacksun

优化J2ME程序大小
by Eric Giguere
February 27, 2002

要把J2ME程序与J2SE程序区分开来,其依据就是J2ME运行所处的受限环境。多数J2ME系统的主要受限条件就是可以存储和运行程序所需内存的大小。例如,许多MIDP设备限制应用程序的尺寸不大于50K,这远远不及Server端J2SE运行环境下那些成兆的程序。实际应用中,程序会很容易超出这些限制条件。通过本篇您将学到一些减小程序尺寸大小的技巧,并在下面的例子中实践这些技术。这个例子MIDlet仅仅显示一个文本框并在其内容改变时发声。

package com.j2medeveloper.techtips;
import javax.microedition.lcdui.*;
public class BeforeSizeOptimization extends
                                       BasicMIDlet {
  public static final Command exitCommand =
                       new Command( "Exit",
                                  Command.EXIT, 1 );
  public BeforeSizeOptimization(){
  }
  protected void initMIDlet(){
      getDisplay().setCurrent( new Mainform() );
  }
  public class Mainform extends form {
      public Mainform(){
          super( "Mainform" );
          addCommand( exitCommand );
          append( textf );
          setCommandListener( new CommandListener(){
              public void commandAction( Command c,
                                     Displayable d ){
                  if( c == exitCommand ){
                      exitMIDlet();
                  }
              }
            }
          );
          setItemStateListener(
                            new ItemStateListener() {
              public void itemStateChanged(
                                         Item item ){
                  if( item == textf ){
                      AlertType.INFO.playSound(
                                      getDisplay() );
                  }
              }
            }
          );
      }

      private TextField textf =
                new TextField( "Type anything", null,
                               20, 0 );
  }
}
虽然这个MIDlet在此仅作为一个例子,但使用的尺寸优化技巧可以适用于任一J2ME的profile上。
注意,上面的MIDlet类需要下面的辅助类:
package com.j2medeveloper.techtips;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public abstract class BasicMIDlet extends MIDlet {
  private Display display;
  public BasicMIDlet(){
  }
  protected void destroyApp( boolean unconditional )
                  throws MIDletStateChangeException {
      exitMIDlet();
  }
  public void exitMIDlet(){
      notifyDestroyed();
  }
  public Display getDisplay(){ return display; }
  protected abstract void initMIDlet();
  protected void pauseApp(){
  }
  protected void startApp()
                  throws MIDletStateChangeException {
      if( display == null ){
          display = Display.getDisplay( this );
          initMIDlet();
      }
  }
}
用J2ME WTK打包时,本例子MIDlet占用4K空间。

减小尺寸的首要步骤就是通过修正程序的功能实现来去掉多余的类。程序的所有功能确实必须都实现吗?用户可以不需要这些“附属功能”吗?要设计尽可能小的程序,这里的MIDlet例子已经相当小了。

第二步就是深入考察程序定义的内部类,特别是匿名类。记住,每个类文件都有一定量的与之相关的系统开销。即便最普通的类也有系统开销。
  public class foo {
      // nothing here
  }
编译上边的类,生成的类文件大约200byte大小。比如实现一个事件监听器,就是对匿名类的常见使用。在例子MIDlet中就定义了两个此类的监听器。接下来进行的最简单的优化就是,让主MIDlet类实现CommandListener和ItemStateListener接口,并把监听器代码移至此处。记住,多个对象可以使用同样的监听器。必要时,可以使用传递至commandAction和itemStateChanged方法的参变量来区分它们。
内部类也可使代码过大,因为编译器必须生成特殊的变量和方法,以便内部类可以访问包含它们的类的私有内容。请参考内部类的规范以获取更多信息。

第三步,尽量使用现有的类。例如,基于CLDC的profile没有构造集合类,所以我们可以用内建的Hashtable和Vector类来实现之。构造MIDP程序时也可采用此法。例子MIDlet中定义了一个form字类来生成主表,可以容易的如下直接生成:
  mainform = new form( "Mainform" );
  mainform.addCommand( okCommand );
  mainform.setCommandListener( listener );
这里没有正确或者错误的答案,只是要推敲。

第四步就是破坏程序的继承关系。你也许把相关的代码放到一个或多个抽象类中,这是OOD中为提高程序间代码重用的推荐做法。虽然破坏继承关系与你所学知识相违背,但简化的继承关系更有意义。特别的,当你的的抽象类――可能来自其他项目――仅仅被继承一次时,破坏继承关系的结果不言而喻。例如,例子MIDlet继承了BasicMIDlet类,但两者合并为一个类。

第五步就是要缩短名字长度,如包名、类名、方法名和数据元素名。看起来有些蠢,但一个类文件确实包含太多的符号信息。缩短各量的名字可以缩小生成的类文件尺寸。这种节省不会特别明显,但多个类中进行总加的结果还是可观的。包名对减小尺寸来讲特别合适。MIDP程序是完全自我包容的,完全可以不使用包名,因为在手持设备上包名根本不可能与其他类名冲突。例子MIDlet中,可以把com.j2medeveloper.tchtips包名去掉。
注意,一般来讲,缩短名字不需要手工去做,要用一个“混淆器”去做。“混淆器”的主要功能是“隐藏”程序代码,使之不能通过反编译读出。它的副作用是减小了程序的尺寸。因为隐藏过程主要通过更改方法和数据成员的名字来完成。有一个开源的混淆器称为RetroGuard,可以免费从http://www.retrologic.com得到。也有一些商业包可用。(当为基于CLDC的profile混淆时,记得在预校验之前混淆,否则混淆器将使类文件中的预校验数据失效。)

最后,深入数组的初始化。(例子MIDlet没有做数组初始化,但对程序来说初始化是重要的一步) 在编译时,一个数组初始化声明如下所示:
  int arr[] = { 0, 1, 2, 3 };
而实际生成代码的过程如下所示:
  arr[0] = 0;
  arr[1] = 1;
  arr[2] = 2;
  arr[3] = 3;
这个过程可以通过使用Java 2 SDK中附带的javap工具把二进制代码反编译成类文件去看(使用-c选项)。也许你会诧异于看到的内容,特别当你希望看到的是一排排二进制常数时。有两种方法可以让你看不到反编译的程序代码,(1)把数据编码为字符串,运行时解码之,或者(2)把数据存为二进制文件并与程序打包,用类装载器的getResourceAsStream方法在运行时存取之。

以上只是一些指导性的方法,对每个J2ME程序而言,这里没有具体到步骤。但是多数方法可以应用的本例。优化后的MIDlet如下所示:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class ASO extends MIDlet
               implements CommandListener,
                          ItemStateListener {
  private Display   display;
  private form      mainform;
  private TextField mainformTF =
                new TextField( "Type anything", null,
                               20, 0 );
  public static final Command exitCommand =
                       new Command( "Exit",
                                   Command.EXIT, 1 );
  public ASO(){
  }
  public void commandAction( Command c,
                             Displayable d ){
      if( c == exitCommand ){
          exitMIDlet();
      }
  }
  protected void destroyApp( boolean unconditional )
                  throws MIDletStateChangeException {
      exitMIDlet();
  }
  public void exitMIDlet(){
      notifyDestroyed();
  }
  public Display getDisplay(){ return display; }
  protected void initMIDlet(){
      mainform = new form( "Mainform" );
      mainform.addCommand( exitCommand );
      mainform.setCommandListener( this );
      mainform.setItemStateListener( this );
      mainform.append( mainformTF );
      getDisplay().setCurrent( mainform );
  }
  public void itemStateChanged( Item item ){
      if( item == mainformTF ){
          AlertType.INFO.playSound( getDisplay() );
      }
  }
  protected void pauseApp(){
  }
  protected void startApp()
                  throws MIDletStateChangeException {
      if( display == null ){
          display = Display.getDisplay( this );
          initMIDlet();
      }
  }
}


关于作者:Eric Giguere是来自Sybase下属iAnywhere Solutions的软件开发人员。他致力于手持设备和无线计算领域的Java技术。他是滑铁卢大学的数学学士和数学硕士,写了很多有关计算的文章。
 

 

 

 

 
 

0 0

相关博文

我的热门文章

img
取 消
img