From c3839d3242f6c1b38a83268dd03b78e40e6a51ab Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 18 Jan 2011 17:13:06 -0800 Subject: [PATCH] Minor updates. Take into account Gingerbread JIT and GC improvements. Change-Id: I170def3ac1ecac0ba88258b8d6bfdd77cb2f7f9a --- .../guide/practices/design/performance.jd | 111 +++++++----------- 1 file changed, 41 insertions(+), 70 deletions(-) diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd index 97b31cfa911b2..fe69d7d5e0003 100644 --- a/docs/html/guide/practices/design/performance.jd +++ b/docs/html/guide/practices/design/performance.jd @@ -8,14 +8,13 @@ page.title=Designing for Performance
  1. Introduction
  2. Optimize Judiciously
  3. -
  4. Avoid Creating Objects
  5. +
  6. Avoid Creating Unnecessary Objects
  7. Performance Myths
  8. Prefer Static Over Virtual
  9. Avoid Internal Getters/Setters
  10. Use Static Final For Constants
  11. Use Enhanced For Loop Syntax
  12. -
  13. Avoid Enums Where You Only Need Ints
  14. -
  15. Use Package Scope with Inner Classes
  16. +
  17. Consider Package Instead of Private Access with Inner Classes
  18. Use Floating-Point Judiciously
  19. Know And Use The Libraries
  20. Use Native Methods Judiciously
  21. @@ -83,27 +82,31 @@ without.

    test on that device.

    -

    Avoid Creating Objects

    +

    Avoid Creating Unnecessary Objects

    Object creation is never free. A generational GC with per-thread allocation pools for temporary objects can make allocation cheaper, but allocating memory is always more expensive than not allocating memory.

    If you allocate objects in a user interface loop, you will force a periodic -garbage collection, creating little "hiccups" in the user experience.

    +garbage collection, creating little "hiccups" in the user experience. The +concurrent collector introduced in Gingerbread helps, but unnecessary work +should always be avoided.

    Thus, you should avoid creating object instances you don't need to. Some examples of things that can help:

    A somewhat more radical idea is to slice up multidimensional arrays into @@ -119,7 +122,7 @@ parallel single one-dimension arrays:

    generally much better than a single array of custom (Foo,Bar) objects. (The exception to this, of course, is when you're designing an API for other code to access; in those cases, it's usually better to trade - correct API design for a small hit in speed. But in your own internal + good API design for a small hit in speed. But in your own internal code, you should try and be as efficient as possible.) @@ -127,6 +130,7 @@ parallel single one-dimension arrays:

    can. Fewer objects created mean less-frequent garbage collection, which has a direct impact on user experience.

    +

    Performance Myths

    @@ -265,43 +269,18 @@ hand-written counted loop for performance-critical ArrayList iteration.

    (See also Effective Java item 46.)

    - -

    Avoid Enums Where You Only Need Ints

    - -

    Enums are very convenient, but unfortunately can be painful when size -and speed matter. For example, this:

    - -
    public enum Shrubbery { GROUND, CRAWLING, HANGING }
    - -

    adds 740 bytes to your .dex file compared to the equivalent class -with three public static final ints. On first use, the -class initializer invokes the <init> method on objects representing each -of the enumerated values. Each object gets its own static field, and the full -set is stored in an array (a static field called "$VALUES"). That's a lot of -code and data, just for three integers. Additionally, this:

    - -
    Shrubbery shrub = Shrubbery.GROUND;
    - -

    causes a static field lookup. If "GROUND" were a static final int, -the compiler would treat it as a known constant and inline it.

    - -

    The flip side, of course, is that with enums you get nicer APIs and -some compile-time value checking. So, the usual trade-off applies: you should -by all means use enums for public APIs, but try to avoid them when performance -matters.

    - -

    If you're using Enum.ordinal, that's usually a sign that you -should be using ints instead. As a rule of thumb, if an enum doesn't have a -constructor and doesn't define its own methods, and it's used in -performance-critical code, you should consider static final int -constants instead.

    - -

    Use Package Scope with Inner Classes

    +

    Consider Package Instead of Private Access with Private Inner Classes

    Consider the following class definition:

    public class Foo {
    +    private class Inner {
    +        void stuff() {
    +            Foo.this.doStuff(Foo.this.mValue);
    +        }
    +    }
    +
         private int mValue;
     
         public void run() {
    @@ -313,24 +292,19 @@ constants instead.

    private void doStuff(int value) { System.out.println("Value is " + value); } - - private class Inner { - void stuff() { - Foo.this.doStuff(Foo.this.mValue); - } - } }
    -

    The key things to note here are that we define an inner class (Foo$Inner) -that directly accesses a private method and a private instance field -in the outer class. This is legal, and the code prints "Value is 27" as -expected.

    +

    The key things to note here are that we define a private inner class +(Foo$Inner) that directly accesses a private method and a private +instance field in the outer class. This is legal, and the code prints "Value is +27" as expected.

    -

    The problem is that the VM considers direct access to Foo's private members -from Foo$Inner to be illegal because Foo and Foo$Inner are different classes, -even though the Java language allows an inner class to access an outer class' -private members. To bridge the gap, the compiler generates a couple of -synthetic methods:

    +

    The problem is that the VM considers direct access to Foo's +private members from Foo$Inner to be illegal because +Foo and Foo$Inner are different classes, even though +the Java language allows an inner class to access an outer class' private +members. To bridge the gap, the compiler generates a couple of synthetic +methods:

    /*package*/ static int Foo.access$100(Foo foo) {
         return foo.mValue;
    @@ -339,22 +313,19 @@ synthetic methods:

    foo.doStuff(value); }
    -

    The inner-class code calls these static methods whenever it needs to -access the "mValue" field or invoke the "doStuff" method in the outer -class. What this means is that the code above really boils down to a case -where you're accessing member fields through accessor methods instead of -directly. Earlier we talked about how accessors are slower than direct field +

    The inner class code calls these static methods whenever it needs to +access the mValue field or invoke the doStuff method +in the outer class. What this means is that the code above really boils down to +a case where you're accessing member fields through accessor methods. +Earlier we talked about how accessors are slower than direct field accesses, so this is an example of a certain language idiom resulting in an "invisible" performance hit.

    -

    We can avoid this problem by declaring fields and methods accessed -by inner classes to have package scope, rather than private scope. -This runs faster and removes the overhead of the generated methods. -(Unfortunately it also means the fields could be accessed directly by other -classes in the same package, which runs counter to the standard -practice of making all fields private. Once again, if you're -designing a public API you might want to carefully consider using this -optimization.)

    +

    If you're using code like this in a performance hotspot, you can avoid the +overhead by declaring fields and methods accessed by inner classes to have +package access, rather than private access. Unfortunately this means the fields +can be accessed directly by other classes in the same package, so you shouldn't +use this in public API.

    Use Floating-Point Judiciously