REGRESSING OBJECT-ORIENTED PRINCIPLES TO ACHIEVE PERFORMANCE GAINS ON THE JAVA PLATFORM, MICRO EDITION Except where reference is made to the work of others, the work described in this thesis is my own or was done in collaboration with my advisory committee. This thesis does not include proprietary or classified information. _________________________________________________ Sean Christopher Cook Certificate of Approval: ___________________________ ___________________________ Richard Chapman David A. Umphress, Chair Associate Professor Associate Professor Computer Science and Computer Science and Software Engineering Software Engineering ___________________________ ____________________________ John A. Hamilton, Jr. Joe F. Pittman Associate Professor Interim Dean Computer Science and Graduate School Software Engineering REGRESSING OBJECT-ORIENTED PRINCIPLES IN ORDER TO ACHIEVE PERFORMANCE GAINS THE JAVA PLATFORM, MICRO EDITION Sean Christopher Cook A Thesis Submitted to the Graduate Faculty of Auburn University in Partial Fulfillment of the Requirements for the Degree of Master of Science December 15 th , 2006 Auburn, Alabama iii REGRESSING OBJECT-ORIENTED PRINCIPLES TO ACHIEVE PERFORMANCE GAINS ON THE JAVA PLATFORM, MICRO EDITION Sean Christopher Cook Permission is granted to Auburn University to make copies of this thesis at its discretion, upon request of individuals or institutions and at their expense. The author reserves all publication rights. ______________________________ Signature of Author ______________________________ Date of Graduation iv THESIS ABSTRACT REGRESSING OBJECT-ORIENTED PRINCIPLES TO ACHIEVE PERFORMANCE GAINS ON THE JAVA PLATFORM, MICRO EDITION Sean Christopher Cook Master of Science, December 15, 2006 (B.S. Software Engineering, Auburn University, 2005) 92 Typed Pages Directed by David Umphress Object-Oriented Programming is a software design method that models the characteristics of abstract or real objects using classes and objects [Sun Microsystems 2006b]. The Java language is intrinsically object-oriented; in fact Sun Microsystems? definition of Java contains the phrase ?object-oriented? [2006]. It would then be assumed that the Java Platform, Micro Edition would be optimized such that correctly- implemented OO code will run, unmodified, faster than incorrectly-implemented code. This is not the case. Code exhibiting ?good? OO design actually runs slower than equivalent code written in a functional fashion. In short, a Java ME MIDlet which adheres to accepted standards of ?good? object-oriented design can have its execution speed increased by regressing its design. v ACKNOWLEDGEMENTS I would like to sincerely thank my major professor, Dr. David A. Umphress, for providing the funding which made my graduate studies possible. His guidance, feedback, and sense of humor have all made this undertaking a wonderful experience. I would also like to thank my committee members, Dr. Richard Chapman, and Dr. John A. Hamilton, Jr., for their participation on my committee, as well as their tutelage throughout my undergraduate and graduate studies. Thanks are also due to Brad Dennis and William ?Amos? Confer for their outstanding work on the MobileEdition project. In addition, I would like to acknowledge the employees of Rocket Mobile for their comments, suggestions, and code that were used throughout the development of Mobile Edition. This research was supported in part by the National Science Foundation (NSF 0311339) and by Rocket Mobile, Inc. Finally, I would like to express my utmost gratitude to my parents. vi Style manual or journal used: ACM Computing Review Computer software used: Microsoft Office System 2003 vii TABLE OF CONTENTS LIST OF FIGURES???????????????????????????x CHAPTER 1 INTRODUCTION 1.1 Area of research???????????????????????.....1 1.2 Statement of Problem?...????????????????????..4 1.3 Motivation for research?????????????????????..5 CHAPTER 2 STATEMENT OF THE PROBLEM 2.1 Literature Overview?????????????????????.......7 2.1.1 Mobile Software Constraints???????????????..7 2.1.2 Java ME Constraints??????????????????...7 2.1.3 Portability???????????????????????8 2.2 Known performance enhancement techniques for Java ME???..................8 2.2.1 High Level Optimizations????????????????...9 2.2.2 Low Level Optimizations????????????????...9 2.2.3 Class Refactoring???????????????????..10 2.2.4 Garbage Collection optimizations?????????????.10 2.2.5 Obfuscation?????????????????????...11 2.2.6 Optimize the packaging process?????????????...11 viii 2.3 Software tools for Java ME optimization?????????????...11 ix CHAPTER 3 SOLUTION 3.1 Approach??????????????????????????..13 3.2 Canonical Regressions?????????????????????.14 3.2.1 Encapsulation????????????????????....14 3.2.2 Inheritance??????????????????????.17 3.2.3 Polymorphism????????????????????...20 3.3 Side Effects of Canonical Regressions??????????????....23 3.4 Algorithmic Regressions??????????????????..??23 3.4.1 Testing object pools??????????????????..25 3.4.2 Side Effects of Algorithmic Regressions?????????......27 3.5 Architectural Regressions????????????????????28 3.5.1 Architectural Regression Example????????????...28 3.5.2 Side Effects of Architectural Regressions??????..???..29 CHAPTER 4 CASE STUDY 4.1 Overview??????????????????????????..30 4.2 Version History????????????????????????30 4.2.1 Initial Version????????????????????...31 4.2.2 Intermediate Revisions?????????????????.31 4.2.3 Regressed Version???????????????????32 4.3 Optimizations Performed????????????????????.32 4.3.1 Canonical Regressions?????????????????..33 4.3.1.1 Encapsulation?????????????????.33 4.3.1.2 Inheritance??????????????????..34 x 4.3.1.3 Polymorphism?????????????????36 4.3.2 Algorithmic Regressions????????????????...38 4.3.3 Architectural Regressions????????????????.39 4.3.4 Other Optimizations Performed??????????????41 4.4 Results of Optimizations????????????????????..41 4.4.1 Positive Benefits???????????????????...42 4.4.2 Negative Benefits???????????????????..42 4.5 Conclusion?????????????????????????...42 CHAPTER 5 CONCLUSION AND FUTURE WORK 5.1 Overview??????????????????????????..45 5.1.1 The OO Paradox???????????????????...46 5.1.2 Optimize a well-defined application????????????.46 5.2 Future Work?????????????????????????.47 BIBLIOGRAPHY???????????????????????????..49 APPENDIX A?????????????????????????????52 APPENDIX B?????????????????????????????60 xi LIST OF FIGURES Figure 3.1: Class Pre-Regression?????????????????????...15 Figure 3.2: Class Post-Regression?????????????????????.16 Figure 3.3: Comparison of an initial class vs. a canonically-regressed class?????17 Figure 3.4: Inheritance Regression???..?????????????????..18 Figure 3.5: Canonical Regression - Inheritance - Results????????????..19 Figure 3.6: Inheritance test case class diagram????????????????..21 Figure 3.7: Regressing polymorphic function????????????????...21 Figure 3.8: Canonical Regression - Polymorphism??????????????...22 Figure 3.9: Without Algorithmic Regression?????????????????.24 Figure 3.10: With Algorithmic Regression Applied??????????????..25 Figure 3.11: Algorithm Regression via Object Pooling?????????????.26 Figure 4.1: Canonical Regression Example from MobileEdition?????????..34 Figure 4.2: Inheritance in pre-regressed Rocket Mobile????????????...35 Figure 4.3: Interface example from MobileEdition??????????????...36 Figure 4.4: Original registerPageListener??????????????????..37 Figure 4.5: Modified registerPageListener??????????????????37 Figure 4.6: WorkerThread Source Code???????????????????39 Figure 4.7: Comparison of MobileEdition execution times???????????...43 Figure 5.1: Table of Experimentation Results????????????????...45 1 CHAPTER 1 INTRODUCTION 1.1 Area of Research Software developers have recently witnessed a rapid increase in the speed and capacity of hardware, a decrease in its cost, and a proliferation of hand-held consumer electronics devices such as mobile phones and Personal Data Assistants (PDAs). In turn, this has resulted in an increased demand for software applications, outpacing developers? ability to produce them, both in terms of their sheer numbers and the sophistication demanded of them [Mikic-Rakic 2002]. The design and implementation of software for mobile devices is intimately tied to the constraints of the device. In order to overcome the constraints of hand-held devices, mobile software challenges old assumptions and demands novel software engineering solutions including new models, algorithms, and middleware [Roman et al 2000]. While recent and anticipated technological advances in wireless computing will permit users to compute anywhere, mobile platforms are unlikely to have the computational resources to solve even moderately complex problems that users routinely solve on workstations today [Drashanksky, et al 1996]. One mobile platform which has demonstrated continued success and adoption in the mobile marketplace, but is still hindered by its available computational resources, is the Java Platform, Micro Edition 2 (Java ME). Java ME provides a robust, flexible environment for applications running on consumer devices, such as mobile phones, PDAs, TV set-top boxes, printers and a broad range of other embedded devices [Sun 2006]. It is a collection of technologies and specifications that implementers and developers can choose from and combine to construct a complete Java runtime environment that closely fits the requirements of a particular range of devices and target markets. Each combination is optimized for the memory, processing power, and I/O capabilities of a related category of devices [Sun 2006]. The adoption of Java ME-capable devices in the marketplace has helped to drive the need for Java ME software. In a survey of mobile developers, 40% reported that they were using the Java ME platform for wireless development, and another 24% were evaluating the platform for future use [Evans Data Corporation 2004]. These developers are faced with the daunting task of developing quality software that meets the performance expectations of the marketplace while still operating within the constraints of the mobile device, and in turn, the mobile platform, Java ME. 3 In order to meet the needed or expected performance goals of a Java ME application, developers must implement ?novel software engineering solutions? [Roman et al 2000]. This thesis presents a method by which mobile software developers can achieve performance gains in Java ME by relaxing the object-oriented constraints of the software architecture. 1.2 Statement of Problem Object-Oriented Programming is a software design method that models the characteristics of abstract or real objects using classes and objects [Sun Microsystems 2006b]. The Java language is intrinsically object-oriented; in fact Sun Microsystems? definition of Java contains the phrase ?object-oriented? [Sun Microsystems 2006]. As a result, Java developers must create OO code in order to solve problems using the language. It would then be assumed that a Java platform would be optimized such that correctly-implemented OO code could run, unmodified, faster than incorrectly- implemented code. This is not the case. Code exhibiting ?good? OO design actually runs slower than equivalent code written in a functional fashion. In short, a Java ME MIDlet which adheres to accepted standards of ?good? object-oriented design can have its execution speed increased by regressing its design. This regression includes relaxing object-oriented design principles such as encapsulation, polymorphism, and inheritance. As a side-effect of relaxing these design principles, the resulting MIDlet will typically contain fewer physical files, and will be more difficult to maintain. 4 Since regressed OO code is much more difficult to maintain than well-formed code due to its lack of structure, it is beneficial to create a well-formed MIDlet as a baseline and then apply optimizations to it to achieve a final, optimized build of the application. Thus, this is the approach we take in our experimentation. The alternative to this approach would be to implement optimizations throughout the design process, ending with a single, optimized build; however, this optimized build will not lend itself easily to future maintenance. While Java ME developers understand that these optimizations are possible, no research has been performed to establish how much OO design is too much in a Java ME application. This thesis presents a top-down approach for melting a well-formed OO Java ME software design into a more-efficient variant which breaks OO accepted design practices to increase performance. To support this approach, we derive empirical statistics of the effects of key OO design principles, including inheritance, polymorphism, and encapsulation, on the efficiency of a Java ME MIDlet. 1.3 Motivation for Research In the spring of 2004, Auburn University was approached by Rocket Mobile of Los Gatos, California to develop a Java ME version of an existing news reader for mobile devices. Throughout 2004, Brad Dennis and William ?Amos? Confer, both graduate students at Auburn University, designed, tested, and implemented a version of the news reader for Java ME. 5 The initial version of MobileEdition was a well-formed Java ME application but did not perform well enough to be considered a marketable product [Rocket Mobile 2005]. Rocket Mobile engineers tested and profiled the initial application on various handsets and then used this data to pinpoint performance bottlenecks in the application. They then re-wrote and consequently re-structured selected components of the application which resulted in an intermediate version which performed considerably better but still suffered reliability issues. This intermediate version was then returned to the graduate student developers at Auburn University along with general comments on the code base. These comments, as well as extensive handset testing results, were then used in the development of the final version of MobileEdition. The final version of MobileEdition addressed the functional requirements of the application, as well as non-functional requirements, such as performance and responsiveness. Handset-specific errors, such as stalling and crashing, were solved through an extensive testing phase utilizing a Nokia 3650, which was the target device for the application. 6 As MobileEdition?s performance increased, it became clear to the developers that the object-oriented characteristics of the application were slowly deteriorating. The maintainability of the application was clearly decreasing, and the overall program structure lost its rigidity. A post-mortem examination of the final delivered version of MobileEdition revealed three core types of object-oriented regressions which had been applied to the initial version in order to effect a more efficient Java ME application. These regressions fell into three distinguishable categories which were termed canonical, algorithmic, and architectural. 7 CHAPTER 2 LITERATURE SURVEY 2.1 Literature Overview A survey of the literature reveals the key challenges of developing Java ME applications, as well as solutions to these challenges. These challenges, which all result from the limited resources available to Java ME, have been approached with various techniques, or ?optimizations?. These optimizations include high-level, software-based solutions, and low-level, compiler-based solutions. 2.1.1 Mobile Software Constraints An under-lying theme of mobile software literature is that ?pervasive mobile devices have extremely limited memory and storage spaces, requiring us to minimize both the storage and runtime footprints of the application? [Yuan 2004]. 2.1.2 Java ME Constraints Sun Microsystems states that the primary limitation in many Java ME systems is the amount of memory available to store and run applications. Many current MIDP devices, for example, limit application sizes to 50K or less [2002]. 8 Kochnev and Terkhov [2003] present four difficulties of developing Java ME software. First, the size of the Java ME application and its data (many business-class mobile devices with more memory exist, but size is still a problem for an overwhelming majority of phones? including mass-market phones currently produced for entertainment purposes and ?legacy? phones still widely used). Second, intermittent network connections with lower bandwidth present the added challenge of limited communications. Third, small display sizes, which can cause problems for creating an acceptable user interfaces, plague the market. And fourth, primitive facilities for inputting text information further disconnect users from applications. 2.1.3 Portability ?Write once?run anywhere? does not work for a Java ME platform [Kochnev and Terkhov 2003]. Frequent application, porting and tweaking on many devices is still a way of life for Java ME developers because the platform does not correctly address the ?device fragmentation? problem [Yuan 2005]. Tira Wireless has created a commercial software package which automates the portability process [2006]. 2.2 Known Performance Enhancement Techniques for Java ME The known performance enhancements for Java ME target the constraints of the platform, and most are aimed at the limited amount of memory available to the platform. Multiple optimizations are frequently combined to produce a final efficient MIDlet. 9 2.2.1 High Level Optimizations High level optimizations for Java ME should always be considered before attempting low-level optimizations. Examples of high-level optimizations include pre- calculating values, loop optimizations, and using StringBuffer[]?s in place of Strings [Shivas]. 2.2.2 Low Level Optimizations Mike Shivas states that low-level optimizations easily plug into existing code but tend to degrade readability as much as they improve performance. Strength reduction, or replacing a relatively slow operation with a fast one, is a common optimization technique. The most common example is using the bit shift operators, which are equivalent to multiplication and division by a power of two [2005]. 10 2.2.3 Class Refactoring Eric Giguere states that the first step in reducing size in a Java ME application is to remove unnecessary classes by pruning the application's functionality [Sun Microsystems 2002]. One approach suggests that after creating the application?s initial version, you must transform it by merging classes. Technically speaking, this is performed by applying the inline class refactoring pattern. The transformation?s main goal is to remove all user-defined classes from the program so that the final version will contain only standard classes that deal with the user interface, display, timer, and so forth?that is, only the indispensable minimum. The changes amount basically to merging the user-defined classes with standard ones, creating new interfaces, and moving methods to the new class, which results in a ?flat? class model [Kochnev and Terkhov 2003]. 2.2.4 Garbage Collection Optimizations Michael Yuan explains that on mobile devices, due to the small amount of available memory, the garbage collector must run more often. When the garbage collector runs, its thread takes up precious CPU cycles and slows down all other application processes. For effective Java ME applications, the developer must minimize object creation and quickly dispose of objects that are no longer in use. Yuan provides five steps to avoid unnecessary garbage collections in Java ME. First, carefully examine design patterns in early stages of the development cycle. Second, concisely reuse existing objects at the implementation level. Third, use arrays and StringBuffers. Fourth, close network connections, file handlers, and Record Management System (RMS) record 11 stores quickly after use. And finally, free resources when using native libraries, especially since native libraries are not subject to garbage collection [2004]. 2.2.5 Obfuscation In Java ME, obfuscation can help protect applications that are deployed to millions of devices. Importantly, but often forgotten, obfuscation can also help developers with some other equally important issues?namely application size and performance [White 2004]. 2.2.6 Optimize the Packaging Process In the packaging process, developers should include only the classes they actually use. They can do this manually for smaller libraries or use automatic tools bundled with some Java ME IDEs for large libraries. If they want to further reduce the binary application size, they can use a bytecode obfuscator to replace long variable names and class names with shorter, cryptic ones. Since the MIDP runtime loads classes only as needed, applications can be partitioned into separate parts to reduce the runtime footprint. For MIDP applications, the MIDlet suite can contain several relatively independent MIDlets [Yuan 2004]. 2.3 Software Tools for Java ME Optimization The complexity of existing optimization solutions led to the development of many automated software tools which target Java ME optimizations. Innaworks? mBooster is an ?automated optimizer for Java ME applications.? At the core of mBooster is 12 proprietary optimizing Java compiler [2006]. Another automated tool, jPRESTO performs obfuscation, code reduction, class amalgamation, and image optimization [S5 Systems]. 13 CHAPTER 3 SOLUTION 3.1 Approach Our solution to inefficient Java ME applications involves first developing a well- formed object-oriented MIDlet. Once this MIDlet meets all of its functional requirements, its developers can then address non-functional requirements, such as required performance standards, through optimizations to the code base. The developers should start by regressing the core object-oriented features of the system?encapsulation, inheritance, and polymorphism. Next, the developer should identify easily comprehensible code segments which can be replaced with a more efficient segment which may not be as easy to comprehend. Finally, the developer should consider entire components of the application which can be replaced by more efficient variants. 14 3.2 Canonical Regressions Canonical regressions are the simplest changes that can be made to a well-formed Java ME application in order to achieve performance gains. These changes involve modifying encapsulation, inheritance, or the polymorphism in an application. These changes to an application?s structure greatly affect the maintainability of the application while flattening, or simplifying the overall structure. Due to their simplicity, target areas in code where these regressions can be applied are immediately recognizable to developers. Each type of canonical regression was shown through experimentation to increase the performance of a test application. 3.2.1 Encapsulation An example of a canonical regression is the removal of getters and setters in favor of implementing publicly-accessible members in a class. Once this canonical regression has been applied to a class, every other class which utilizes the members of the class must be modified. The negative effects of changing the code base are minimal from a code maintenance standpoint since developers can understand ?x=object.x? to mean ?x=object.getX()?. Figure 3.1 presents a normal, unoptimized Java ME class which requires getters and setters to access and modify its members. Figure 3.2 presents a regressed version of the same class which allows public access to its members, as opposed to getter and setter functions. In addition to the speed increase resulting from removing function calls, the smaller optimized class will help to achieve a smaller overall JAR size. 15 FIGURE 3.1 ? Class Pre-Regression class Circle{ private int x; private int y; private double radius; public Circle(int _x, int _y, int _radius){ this.x=_x; this.y=_y; this.radius=_radius; } public getRadius(){ return radius; } public int getX(){ return x; } public int getY(){ return y; } } 16 FIGURE 3.2 ? Class Post-Regression To test the performance gains brought about by regressing encapsulation, we created a simple class with three members that were accessed via getters and setters. Next, we made an identical class but set each of the three members to public visibility. The source code for our classes is available in Appendix B. We then ran the two classes through identical loops were each member had its value set and read. The results are presented in Figure 3.1.2. The average time between runs for the normal test case was 6.5 milliseconds, while the optimized test case averaged 0.2 milliseconds. The results of testing revealed that the canonically-regressed code segment performed 32.5% faster than the normal code segment. class Circle{ public int x; public int y; public double radius; public Circle(int _x, int _y, int _radius){ this.x=_x; this.y=_y; this.radius=_radius; } } 17 Canonical Regression - Encapsulation 0 1 2 3 4 5 6 7 8 9 1 7 13 19 25 31 37 43 49 55 61 67 73 79 85 91 97 Run # D e lt a ( M illis e c o n d s ) Normal Optimized FIGURE 3.3 - Comparison of an initial class vs. a canonically-regressed class 3.2.2 Inheritance The canonical regression of combining super and subclass functionalities as one requires an application-wide change in how each affected object is handled. For instance, method signatures involving the original sub-class have to be changed to accept the new super-class. To test the effects of regressing inheritance in a Java ME application, we created three classes (see Appendix B). The first two classes are named SuperClass and SubClass and their respective names distinguish their role in a simple inheritance tree. 18 SuperClass provides 10 functions and a single member, x, which are all inherited by SubClass. SubClass defined its own version of function6(), which overrides SuperClass?s function6(). The third class, NoInheritanceClass, has all 9 functions provided by SuperClass and one function, function6(), is the same version provided by SubClass. Figure 3.4 provides a UML diagram of the class structures. FIGURE 3.4 - Inheritance Regression 19 To test the three classes, we first measured the amount of time required to create an instance of SubClass and then call each of its 10 members. This time was then averaged across 1000 runs and the average delta time in milliseconds was recorded. We repeated this process 100 times. Next, we measured the amount of time required to create an instance of NoInheritanceClass and then call each of its 10 members. This time was averaged across 1000 runs and once again, this average delta time was recorded. This process was repeated 99 more times and average delta times were recorded. Figure 3.5 presents a graph of the results of the test. The average delta running time of the SubClass was 0.62ms. The average delta running time of the NoInheritanceClass was 0.0005ms. Thus, for this simplistic example regressing inheritance provided a roughly 1200% speed increase. Canonical Regression - Inheritance 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 1 8 15 22 29 36 43 50 57 64 71 78 85 92 99 Run # D e l t a T i m e ( m s) With Inheritance Without Inheritance FIGURE 3.5 Canonical Regression - Inheritance - Results 20 3.2.3 Polymorphism Modifying polymorphism in an application through canonical regressions helps to eliminate run-time decisions which can greatly affect the performance of a Java ME application. Care must be taken to ensure that all prior contracts or interfaces between classes are still upheld. The resulting application trades code elegance for execution efficiency, which can adversely affect the maintainability of the application. To test polymorphism, we created three classes: Widget, SmallWidget, and BigWidget, where SmallWidget and BigWidget both extended the Widget class. Figure 3.6 presents the class diagram for SmallWidget and BigWidget. To handle these three classes polymorphically, we created a WidgetWorker function which takes an argument of type Widget. To handle these three classes without polymorphism, we created two functions, SmallWidgetWorker and BigWidgetWorker, which operate on their respective object types. 21 FIGURE 3.6 ? Inheritance test case class diagram private void widgetWorker(Widget w) { w.getDescription(); w.setDescription("foo"); w.busyWidgetWork(); } private void smallWidgetWorker(SmallWidget w) { w.getDescription(); w.setDescription("foo"); w.busyWidgetWork(); } private void bigWidgetWorker(BigWidget w) { w.getDescription(); w.setDescription("foo"); w.busyWidgetWork(); } FIGURE 3.7 ? Regressing a polymorphic function 22 For our polymorphic test case, we first create a SmallWidget and a BigWidget. Then for 100 iterations we average the amount of time it takes to call WidgetWorker with both classes 1000 times. For our test case without polymorphism, we perform the same procedure except we call the SmallWidgetWorker and BigWidgetWorker functions respectively. The average delta time for the polymorphic test case was 1.7ms, while the average delta time for the regressed test case was 0.002ms. Thus, for this simple example the performance increase was 970%. Figure 3.8 charts the difference in average delta times between the two test cases over their 100 iterations. Canonical Regression - Polymorphism 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.1 2.2 1 8 15 22 29 36 43 50 57 64 71 78 85 92 99 Run # T i m e D e lt a ( m s) With Polymorphism Without Polymorphism FIGURE 3.8 ? Canonical Regression - Polymorphism 23 3.3 Side Effects of Canonical Regressions The most obvious side effect of canonical regressions is the invalidation of core OO principles. For example, by removing getters and setters from the classes in a MIDlet, the developer is invalidating the principle of encapsulation. If an application is initially developed following traditional ?data-hiding? techniques, replacing calls to simple getters and setters will not affect data integrity in the application. This point emphasizes one of the reasons why it is necessary to apply OO regressions after a well- formed application has been created, and not during the development process. A positive unintended side effect of removing getters and setters is smaller JAR file sizes. The JAR file size is frequently mentioned as a starting point for optimizing Java ME code [Sun 99]. By removing two functions per every member in a class throughout an application the developer is effectively trimming the size of the JAR. The effect of canonical regressions on the maintenance of a MIDlet is substantial. As a result, maintenance changes will need to be analyzed by the developer before implementation so that he can determine whether or not the regressed MIDlet or the baseline MIDlet should be the target of the maintenance update. If he decides to return to the baseline MIDlet, a new optimization process will need to be applied after maintenance is complete. 3.4 Algorithmic Regressions The purpose of an algorithmic regression is to replace a slower, easily comprehensible code segment with a more efficient segment which may not be as easy to comprehend. An example of an algorithmic regression in Java ME is an object pool. An 24 object pool instantiates a group of related objects at a pre-determined time in an application rather than allowing the application to instantiate each individual object as it is needed. The efficiency of pooling objects compared to creating and disposing of objects is highly dependent on the size and complexity of the objects [Muir 2002]. To understand the functionality of an object pool, consider the following scenario: A developer wishes to develop a mobile web browser which downloads page content, parses the content, and then displays the content. For each image that is found in the content, the developer will need to store the image content into an image object and then display that object. To do this, he can either create a new image object each time from the heap or re-use a previous image object that is stored in an object pool. //download and parse content //create image objects to display for( i=0; i * There should be a separate pool for each type of object to be pooled. *

* The ArrayPoolManager is not synchronized. */ public class ArrayPoolManager { /** * Array to hold objects that are ready for use. */ private Object[] m_Pool; /** * The capacity of the object pool. */ private int m_Capacity; 87 /** * The next available object; -1 means that the pool is empty. */ private int m_NextAvail = -1; /** * Creates a pool of objects, with an initial capacity. */ public ArrayPoolManager(int capacity) { m_Capacity = capacity; m_Pool = new Object[m_Capacity]; } /** * Gets an object from the pool if one is available; null otherwise. * * @return An object from the pool if one is available; null otherwise. */ public Object getObject() { /* Check to see if an object is available to be returned */ if (m_NextAvail >= 0) { // makes sure that the object is released from the array // so that only the caller has a reference, in case it is // not put back into the pool Object t = m_Pool[m_NextAvail]; 88 m_Pool[m_NextAvail--] = null; return t; } return null; } /** * Puts an object back into the pool, if there is room for it. * * @param obj * The object to be put back into the pool. */ public void putObject(Object obj) { if (m_NextAvail < m_Capacity) { m_Pool[++m_NextAvail] = obj; } } } 89 PoolTestObject.java: package edu.auburn.pool; public class PoolTestObject { private int m_int = -1; private String m_str = ""; public PoolTestObject() { m_int = 99; m_str = "Foobar"; } public void doAction() { String result = m_str + Integer.toString(m_int); } } 90 CircleOptimized.java: package edu.auburn.unoptimized; import edu.auburn.interfaces.Circle; public class CircleOptimized implements Circle{ private double x; private double y; private double radius; public CircleOptimized(double x, double y, double radius) { this.x = x; this.y = y; this.radius = radius; } public double getRadius() { return radius; } public double getX() { return x; 91 } public double getY() { return y; } public double calcArea() { return 3.14 * radius * radius; } } 92 EncapsulationOptimized.java: package edu.auburn.unoptimized; public class EncapsulationOptimized { public String name = ""; public int intNumber = 0; public double longNumber = 0.0; public EncapsulationOptimized() { super(); // TODO Auto-generated constructor stub } public void doOperation() { for (int i = 0; i < 100; i++) { intNumber = intNumber * 1; } } }