顯示具有 performance 標籤的文章。 顯示所有文章
顯示具有 performance 標籤的文章。 顯示所有文章

2013年2月21日 星期四

[Android] Optimised ImageView

在 4.0 前,使用 ImageView.setImageDrawable(),會執行下列動作:
  1. Set the new Drawable (and keep a reference to it).
  2. Request a layout pass.
  3. Invalidate itself to display the new contents.

step 1 and step 3 是必要的
step 2 是定位 drawable 自 ImageView 中的位置,因此只需要在 drawable 大小改變時使用到。

也就是若 AdapterView 中使用的都是大小相同的 drawable,則能省略 step 2,讓滑動的效能獲得改善


在 4.0 中會先比對大小才呼叫 requestLayout()(run the step 2),4.0 後則能使用 reference 中所提供的 OptimisedImageView。


Relative post
- [Android] Avoid Memory leak


* Reference
- Snippet: ImageView Layout Optimisation | senab

2013年1月6日 星期日

[SQL] 分頁 performance


select * from(
  select x.*, rownum r from(
    ...
  )x
)y where y.r >= 1 and y.r <= 10


select * from (
  select row_.*, rownum rownum_ from (
    ...
  ) row_ where rownum <= 10
) where rownum_ > 0

寫法二會比寫法一快很多

而 JPA 的 Query setFirstResult(), setMaxResults() 生成的分頁 SQL 就會是寫法二

但 rownum <= 的值越大,查詢時間會越久

所以翻頁翻到越後面 頁面顯示的速度會越慢

2012年9月15日 星期六

[Android] Memory Cache

Reference
  • reference 的可以分為多種強度,我們最熟悉和最常使用的是 strong reference。
  • Four different degrees of reference strength: strong, soft, weak, and phantom.
  • 強度的差異在於 reference 和 garbage collector 間的互相影響關係。

Strong Reference
// buffer 就是 strong reference
StringBuffer buffer = new StringBuffer();
  • 當 reference 指向一個以上的物件,便是 strong reference。
  • 可以防止此 reference 被 GC。
  • 缺點:
    • Memory: 因為使得物件不能被回收,所以有造成 memory leak 的危險。
    • Caching: 假設在 application 中應用到許多大圖片,為了一直 reload 而 cache 圖片,所以 always 會有 reference 指向圖片,使得它在 memory 且不會被回收,也就是說我們得決定它是否該被移除且使其可以回收。

WeakReference
weak reference 則是隨時有可能已被回收。
// API 使用方式如下,建立 Widget 的 WeakReference。
WeakReference weakWidget = new WeakReference<widget>(widget);
// 取出 Widget object。
// 注意: 因為物件可以被回收,所以可能會得到 null。
weakWidget.get()
WeakHashMap
  • 作用類似 HashMap,只是 key 是使用 weak reference,若 key 變成 garbage 則它的 entry 便自動會被移除。
  • 但並不是你啥也也沒做他就能自動釋放,而是你使用到 value 才會被釋放。
  • super(key, queue); 只有 key 才是 weak reference,value 仍是 strong reference,所以 System.gc() 後,key 會被清除,value 則是才被視為 weak reference 然後到被調用到了才會被清除。

Reference queues
  • 當 WeakReference 回傳 null 時表示指向的物件已被回收,WeakReference object 也無用了,所以如 WeakHashMap 會去移除這類的 WeakReference object,避免 WeakHashMap 一直成長,其中卻有很多無用的 WeakReference 。
  • ReferenceQueue 可以幫助你管理這些 dead reference。
    • 如果你將 ReferenceQueue 傳入 weak reference's constructor,當有 reference 指向的物件被回收時,該 reference 會自動被 insert 到 ReferenceQueue 中,所以你可以定期清裡 ReferenceQueue 也就會清理了 dead reference。

Soft references
  • 類似於 weak reference,差異是比 weak reference 不易被回收。
  • 因為 soft reference 會盡量被保留在 memory 所以適合做 image cache。

Phantom References
  • Its get() method always returns null.
  • 用處:
    • 可以讓你決定何時將物件從 memory 移除。ex: manipulating large images,你可以先確定現在這一張已被移除,再載入下一張以避免 OOM。
    • 避免 finalize() method 可以 "resurrect" 建立了 strong reference 的 object。
      • override finalize() 的物件至少要被視為 GC 對象兩次以上才能被回收到,而不能及時的被回收,也因此會有多個待回收的 garbage 存在著等著被回收。

Android itself employs some caching as part of the resources infrastructure, so you are already getting the benefit of memory caching.

使用 bitmap 時,記得使用 recycle(),可以幫助釋放空間,所以若是再呼叫 getPixels() or setPixels(),可能會得到 exception,所以建議當不會再使用到 bitmap 時再使用。

LruCache
  • API level 12 (3.1)
  • Support Library back to API level 4 (1.6).
  • 管理與 cache 物件,呼叫 get(key) 取出物件,若物件不存在則會呼叫 create() 產生物件,並將新產生的物件加入 head of cache 再將其回傳。
  • 加入新物件時,cache 會檢查是否超過指定的大小,若超過則會刪除最後一筆 (tail of cache list)。

// override 這個 method 可以讓我們決定 cache 中每個物件 size 怎麼計算,default returns 1。
@Override
protected int sizeOf( String key, Bitmap value )
{
    return value.getByteCount();
}

Note:
Bitmap#getByteCount()
  • Supported from API Level 12。
// 建構子中則傳入想預設此 cache 的大小,這裡設定最大為 5 M。
// 所以一旦超過 5 M,物件會從最後一直被移除直到總大小小於 5 M。
public LruMemoryCache(Context context)
{
    super( 5 * 1024 * 1024 );
    this.context = context;
}

為避免發生 OutOfMemoryError,在系統呼叫 onLowMemory() 時建議呼叫 LruCache#evictAll() 移除所有元素再重建。

Note:
  • onLowMemory() 會被呼叫是因為整個系統的空間不足而不是因為你的 App 所用的空間已不足!
    • 所以等到此 method 被呼叫時已來不及,更好的方式是在 App 執行一開始便設定適當的大小限制給它。
    • ActivityManager#getMemoryClass() (API Level 5) 可以取得該 application 在 該 device 中的分配空間:
      • 單位為 megabytes。
      • 預設為 16 M,空間大點裝置可到 24 或更高。

也可以利用 LruCache 來管理在 SD card 中的檔案大小:
  • 儲存 File object 在 LruCache(override create())。
  • 以 file.length() 計算檔案大小 (override sizeOf())。
  • 移除物件時刪除 SD card 中的檔案 (override entryRemoved())。


* Reference
- Understanding Weak References | Java.net
- Styling Android » Blog Archive » Memory Cache – Part 1
- Styling Android » Blog Archive » Memory Cache – Part 2
- Styling Android » Blog Archive » Memory Cache – Part 3
- Styling Android » Blog Archive » Memory Cache – Part 4
- WeakHashMap的神话 - - ITeye技术网站
- WeakHashMap是如何清除不用的key的

2012年4月15日 星期日

[AndroidDev] Designing for Performance

  • Battery life is one reason you might want to optimize your app even if it already seems to run “fast enough”.
  • Choosing the right algorithms and data structures should always be your priority.
    • Using the right data structures and algorithms will make more difference than any of the advice here
  • Considering the performance consequences of your API decisions will make it easier to switch to better implementations later (this is more important for library code than for application code).
  • Different versions of the VM running on different processors running at different speeds.
  • There are also huge differences between devices with and without a JIT: the “best” code for a device with a JIT is not always the best code for a device without.

There are two basic rules for writing efficient code:
  • Don’t do work that you don’t need to do.
  • Don’t allocate memory if you can avoid it.


Avoid Creating Unnecessary Objects *
過多物件會占據太多空間,觸使系統 GC 的頻率變高,而在 GC 時會使得使用者在操作中感覺頓頓的,因為系統會暫停(lock)所有東西。
  • Fewer objects created mean less-frequent garbage collection, which has a direct impact on user experience.
  • If you allocate objects in a user interface loop, you will force a periodic garbage collection, creating little “hiccups” in the user experience.
  • 改善範例: 
    • 如果回傳的字串會再 append 到 StringBuffer,那麼可以直接傳入 StringBuffer 去 append 字串。
    • When extracting strings from a set of input data, try to return a substring of the original data, instead of creating a copy. You will create a new String object, but it will share the char[] with the data. (The trade-off being that if you’re only using a small part of the original input, you’ll be keeping it all around in memory anyway if you go this route.)
    • 使用一維矩陣取代多維矩陣;使用 primitive types array instead of Object type array. 
      • But this also generalizes to the fact that two parallel arrays of ints are also a lot more efficient than an array of (int,int) objects.
      • But tuples of two-dimension objects is usually better to trade good API design for a small hit in speed. 

Performance Myths
  • On devices without a JIT
    • 型別有指定特定的 type 會比使用 interface 有效率。For example, it was cheaper to invoke methods on a HashMap map than a Map map, even though in both cases the map was a HashMap
    • Caching field accesses is about 20% faster than repeatedly accesssing the field. 
  • With a JIT, field access costs about the same as local access, so this isn’t a worthwhile optimization unless you feel it makes your code easier to read. (This is true of final, static, and static final fields too.)

Prefer Static Over Virtual
If you don’t need to access an object’s fields, make your method static.

Avoid Internal Getters/Setters
  • Virtual method calls are expensive, much more so than instance field lookups.
  • It’s reasonable to follow common object-oriented programming practices and have getters and setters in the public interface, but within a class you should always access fields directly.

Use Static Final For Constants
This optimization only applies to primitive types and String constants, not arbitrary reference types. Still, it’s good practice to declare constants static final whenever possible.
// Compiler 會產生  method(a class initializer method),在第一次使用這個 class 時會被執行。
// The method stores the value 42 into intVal, and extracts a reference from the classfile string constant table for strVal.
// When these values are referenced later on, they are accessed with field lookups.
static int intVal = 42;
static String strVal = "Hello, world!";
We can improve matters with the “final” keyword:
// 不會產生  method,因為常數會存在於 dex file 的 static field initializers。
// Code that refers to intVal will use the integer value 42 directly, and accesses to strVal will use a relatively inexpensive “string constant” instruction instead of a field lookup. 
static final int intVal = 42;
static final String strVal = "Hello, world!";

Use Enhanced For Loop Syntax (i.e for-each loop)
  • The enhanced for loop can be used for collections that implement the Iterable interface and for arrays.
  • 只要是 Collection 介面的實作物件,都可以用 foreach 語法,新增於 J2SE 5.0 之後。
// 如果走訪的是陣列,編譯器會自動展開為以下的程式碼:
public void go(int ai[]) {
    int ai1[] = ai;
    int i = ai1.length;
    for (int j = 0; j < i; j++) {
        int k = ai1[j];
        System.out.println(k);
    }
}

// 若是 Collection 的實作物件,其實編譯器會展開為:
public void go(Collection collection) {
    String s;
    for (Iterator iterator = collection.iterator(); 
        iterator.hasNext(); System.out.println(s))
        s = (String)iterator.next();
}

// 無論是 Collection、List 或 Set,展開後皆利用 iterator() 方法傳回 Iterator 物件,
// 並利用 Iterator 來移動、傳回下一個物件,這是 Iterator 模式 的實現。
// 所以其實在 for-each 中會多產生個 Iterator 物件,因此可寫成以下程式。
public void go(Collection collection) {
    if (collection.size() > 0)
        for(String element : collection) {
            System.out.println(element);
        }
}
To summarize:
  • Collections 使用 for-each loop; ArrayList 使用 for loop(?)。
    • Use the enhanced for loop by default, but consider a hand-written counted loop for performance-critical ArrayList iteration.
    • With an ArrayList, a hand-written counted loop is about 3x faster (with or without JIT), but for other collections the enhanced for loop syntax will be exactly equivalent to explicit iterator usage.

Consider Package Instead of Private Access with Private Inner Classes
Inner class 使用 Package(default) modifier,而不要使用 Private。
public class Foo {
    private class Inner {
        void stuff() {
            Foo.this.doStuff(Foo.this.mValue);
        }
    }

    private int mValue;

    public void run() {
        Inner in = new Inner();
        mValue = 27;
        in.stuff();
    }

    private void doStuff(int value) {
        System.out.println("Value is " + value);
    }
}

因為 VM 會認為從 Foo$Inner 直接去存取 Foo 的 private member 是不合法的(Foo and Foo$Inner are different classes),因此 compiler 會產生下列 methods(Accessors),也就是 Foo$Inner 事實上是透過這些 methods 來存取 Foo 中的 private members。
// package
static int Foo.access$100(Foo foo) {
    return foo.mValue;
}
// package
static void Foo.access$200(Foo foo, int value) {
    foo.doStuff(value);
}
Accessors are slower than direct field accesses! 所以將 inner class 宣告為 Package,但這樣也表示此 inner class 可以直被同個 package 下的 classes 存取,因此不可使用在 public API.

Use Floating-Point Judiciously
避免使用 float type。

Know And Use The Libraries

Use Native Methods Judiciously
  • Native code isn’t necessarily more efficient than Java. For one thing, there’s a cost associated with the Java-native transition, and the JIT can’t optimize across these boundaries.
  • Native code is primarily useful when you have an existing native code base that you want to port to Android, not for “speeding up” parts of a Java app.

Closing Notes
  • One last thing: always measure
  • Before you start optimizing, make sure you have a problem. Make sure you can accurately measure your existing performance, or you won’t be able to measure the benefit of the alternatives you try.


* Reference
- Designing for Performance
- 繼承
- Android App開發效能你知多少?
- Dalvik 記憶體管理
- Just-in-time compilation
- 初探JIT compiler 與 Android Dalvik VM
- Profiling with Traceview and dmtracedump
- Java Gossip: autoboxing、 unboxing
- Java Essence: 神奇的 foreach

[Tool] Memory Analyzer Tool (MAT)

雖然現在手機在硬體上的限制已不如從前,效能也大大提升,但手機中的空間還是不比在電腦上,所以如果不需過多的 effort,盡量降低空間的使用仍是必要的,使用者很容易就安裝過多的 App 或是同時操作多個 App,那麼一個 App 能降低一點使用量,我認為全部加起來多少會有點影響,但並不說要在一開始開發時便以效能為一取向,這樣反而有點綁手綁腳,本末倒置了,除非效能是需求之一。

尤其在某些 UI 的操作上,若系統進行 Garbage Collection,則會讓 User 在操作時感覺到頓頓的,另外,圖片上的使用,很容易使得 App Out Of Memory(OOM)(每個 App 被分配的空間是 16M),因此可利用 Eclipse plugin - MAT 來找出在 App 中是那裡使用了大量空間,而且沒有做適當的釋出。

Install
  • Install MAT Plugin on Eclipse - Install New Software
    • http://download.eclipse.org/mat/1.1/update-site/
  • 開啟關閉 App 約五次,來觀察是否有正確的建立與回收物件
  • Dump HPROF file by DDMS
  • Convert HPROF format by Android Tool, hprof-conv
  • Open eclipse perspective, Memory Analyer and File --> Open Heap Dump...

  • Shallow Heap
    • 物件本身的記憶體使用量。
  • Retained Heap
    • 指物件本身 + 參照過來的物件們所使用的記憶體使用量。

如何妥善的使用 bitmap
Displaying Bitmaps Efficiently


* Reference
- 使用MAT(記憶體分析)工具查看Memory Leak ***
- HOWTO: Debug Memory Leak in Android
- Download MAT
- Android Memory Usage
- Avoiding memory leaks - Romain Guy ***
- Attacking memory problems on Android ***

2012年4月1日 星期日

[AndroidDev] merge

  • The <merge /> tag was created for the purpose of optimizing Android layouts by reducing the number of levels in view trees.
  • 如果 root layout 的大小設為和 parent 一樣 (ex: filll_parent)並且沒其他參數調整需求,那麼其實此 root layout 在實質上是沒有作用的,這時候便可以改以 merge 做為你的 root layout,這樣一來 children 便會直接被加在 merge's parent 上而能少拉一層 view。
    • Since our FrameLayout has the same dimension as its parent, by the virtue of using the fill_parent constraints, and does not define any background, extra padding or a gravity, it is totally useless.When the LayoutInflater encounters this tag, it skips it and adds the <merge /> children to the <merge /> parent. (The children will be added directly to the top-level FrameLayout.)
  • 但 merge 是不能用來取代 LinearLayout 的!
    • You could not apply this trick if your layout was using a LinearLayout as its root tag for instance. The <merge /> can be useful in other situations though.

  • The <merge /> tag is extremely useful and can do wonders in your code. However, it suffers from a couple of limitations:
    • <merge /> can only be used as the root tag of an XML layout
    • When inflating a layout starting with a <merge />, you must specify a parent ViewGroup and you must set attachToRoot to true (see the documentation for inflate(int, android.view.ViewGroup, boolean) method)


* Reference
- Layout Tricks: Merging Layouts | Android Developers
- Android里merge和include标签的使用_云开雾散_百度空间

[AndroidDev] Window Backgrounds & UI Speed

In this article, you will discover how to speed up the drawing and the perceived startup time of your activities. Both these techniques rely on a single feature, the window's background drawable.

  • When you setup your user interface by calling setContentView() on an Activity.
  • 該 activity's window 會被加上你所設的 view 以及 Android 為你所建立的 views。(其中最重要的是 DecorView.)
    • Android adds your views to the Activity's window. The window however does not contain only your views, but a few others created for you. (The most important one is, in the current implementation is the DecorView.)
  • The DecorView is the view that actually holds the window's background drawable.
  • 藉由呼叫 getWindow().setBackgroundDrawable() 便可以改變 activity's window background 也就是 DecorView's background drawable.
  • If you are using the standard Android themes, a default background drawable is set on your activities. The standard theme currently used on the T-Mobile G1 uses for instance a ColorDrawable.
  • 但此預設背景其實是會影響效能的!
  • An easy way to make such an application draw faster is to remove the background drawable. Since the user interface is entirely opaque, drawing the background is simply wasteful. Removing the background improves the performance quite nicely.
  • Removing the window's background can be achieved very easily by using a custom theme. To do so, first create a file calledres/values/theme.xml containing the following:
    
        
    
    
  • This trick comes in very handy for any app that uses a MapView, a WebView or any other full screen opaque view.

  • Using a theme to change the window's background is also a fantastic way to improve the perceived startup performance of some of your activities. This particular trick can only be applied to activities that use a custom background, like a texture or a logo.
  • 如果是在 XML layout 或是 onCreate() 中設定背景,那麼 user 開啟 activity 時會先看到 default theme and its dark background. 等到 content view and first layout/drawing 被 inflate 才會顯示你所設定的背景。
    • If this application simply set the wooden background in the XML layout or in onCreate() the user would see the application startup with the default theme and its dark background. The wooden texture would only appear after the inflation of the content view and the first layout/drawing pass.
  • 改善方式:
    • 將背景設定在 activity theme 中,這樣系統在 application 開始時會已最快的速度載入該 theme,所以 user 再也不會先看到 default background。
      • Instead, the application defines the wooden background in a theme, picked up by the system as soon as the application starts. The user never sees the default theme and gets the impression that the application is up and running right away.
    • ex: The same exact trick is used in the Google Maps application that ships with the T-Mobile G1. When the application is launched, the user immediately sees the loading tiles of MapView. This is only a trick, the theme is simply using a tiled background that looks exactly like the loading tiles of MapView.


* Reference
- Android Developers Blog: Window Backgrounds & UI Speed