Shallow vs. Retained Heap
http://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Fconcepts%2Fshallowretainedheap.html
Java堆:Shallow Size和Retained Size
http://blog.csdn.net/kingzone_2008/article/details/9083327
2016年5月9日 星期一
2016年4月15日 星期五
細說 PriorityQueue
PriorityQueue 的用法在網路上有很多資料可以查詢,這裡就不在介紹,
想在這裡說明的是 PriorityQueue 的實作以及要小心避免的錯誤使用方式。
PriorityQueue 如同它的名字一般,多了 Priority 的功能,
在做 offer 的時候會依據物件的 Priority 來加進 Queue 裡,
這裡出現了第一個要注意的地方,有越小 Priority 的物件是排在比較前面的,
也就是說當你透過 poll 來取得物件時,拿到的是當中最小的那個。
那如果想要取得的是 Priority 最大的怎麼辦?
有兩個方法,二擇一:
k = size-1,x = 要插任的物件

而每次做 poll 時,都會呼叫 siftDown 來重新排序物件,過程如下圖所示:
k = 0,x = 最後一個物件

第二個要注意的點來了!
已經加進 PriorityQueue 的物件可以隨意更動 Priority 嗎?
答案是 NO!!
隨意更動物件的 Priority,就破壞了原本樹的排序,接下來不管是 offer 或 poll 可能都是錯誤的結果。
此外,同樣 Priority 的物件是不保證順序的!
想在這裡說明的是 PriorityQueue 的實作以及要小心避免的錯誤使用方式。
PriorityQueue 如同它的名字一般,多了 Priority 的功能,
在做 offer 的時候會依據物件的 Priority 來加進 Queue 裡,
這裡出現了第一個要注意的地方,有越小 Priority 的物件是排在比較前面的,
也就是說當你透過 poll 來取得物件時,拿到的是當中最小的那個。
那如果想要取得的是 Priority 最大的怎麼辦?
有兩個方法,二擇一:
- 把有較大 Priority 的物件,定義較小的比較值。
- compare(T o1, T o2) 方法的結果反過來就行了。
通常我們說當 o1 > o2 時,應該要回傳 > 0,這樣的結果 PriorityQueue 的排序就會是遞增的。如果想要遞減,當 o1 > o2 時,回傳 < 0 就行了。
k = size-1,x = 要插任的物件
587 private void siftUp(int k, E x) { 588 if (comparator != null) 589 siftUpUsingComparator(k, x); 590 else 591 siftUpComparable(k, x); 592 } 594 private void siftUpComparable(int k, E x) { 595 Comparable<? super E> key = (Comparable<? super E>) x; 596 while (k > 0) { 597 int parent = (k - 1) >>> 1; 598 Object e = queue[parent]; 599 if (key.compareTo((E) e) >= 0) 600 break; 601 queue[k] = e; 602 k = parent; 603 } 604 queue[k] = key; 605 } 607 private void siftUpUsingComparator(int k, E x) { 608 while (k > 0) { 609 int parent = (k - 1) >>> 1; 610 Object e = queue[parent]; 611 if (comparator.compare(x, (E) e) >= 0) 612 break; 613 queue[k] = e; 614 k = parent; 615 } 616 queue[k] = x; 617 }每次做 offer 時,都會呼叫 siftUp 來把物件加到樹中,過程如下圖所示:

而每次做 poll 時,都會呼叫 siftDown 來重新排序物件,過程如下圖所示:
k = 0,x = 最後一個物件
627 private void siftDown(int k, E x) { 628 if (comparator != null) 629 siftDownUsingComparator(k, x); 630 else 631 siftDownComparable(k, x); 632 } 634 private void siftDownComparable(int k, E x) { 635 Comparable<? super E> key = (Comparable<? super E>)x; 636 int half = size >>> 1; // loop while a non-leaf 637 while (k < half) { 638 int child = (k << 1) + 1; // assume left child is least 639 Object c = queue[child]; 640 int right = child + 1; 641 if (right < size && 642 ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0) 643 c = queue[child = right]; 644 if (key.compareTo((E) c) <= 0) 645 break; 646 queue[k] = c; 647 k = child; 648 } 649 queue[k] = key; 650 } 652 private void siftDownUsingComparator(int k, E x) { 653 int half = size >>> 1; 654 while (k < half) { 655 int child = (k << 1) + 1; 656 Object c = queue[child]; 657 int right = child + 1; 658 if (right < size && 659 comparator.compare((E) c, (E) queue[right]) > 0) 660 c = queue[child = right]; 661 if (comparator.compare(x, (E) c) <= 0) 662 break; 663 queue[k] = c; 664 k = child; 665 } 666 queue[k] = x; 667 }

第二個要注意的點來了!
已經加進 PriorityQueue 的物件可以隨意更動 Priority 嗎?
答案是 NO!!
隨意更動物件的 Priority,就破壞了原本樹的排序,接下來不管是 offer 或 poll 可能都是錯誤的結果。
此外,同樣 Priority 的物件是不保證順序的!
2014年12月27日 星期六
[Eclipse] Java was started but returned exit code=13
至從把 Java 從 7 更新到 8 後,開 Eclipse 突然出現了錯誤:
Java was started but returned exit code=13
後來發現 java 更新到 32bit 的版本,但 Eclipse 用的是 64bit 的版本,
2014年10月22日 星期三
Use Enum to implement finite state machine
範例:
public enum StateMachine {
INITIAL {
@Override
public StateMachine next() {
return SECOND;
}
},
SECOND {
@Override
public StateMachine next() {
return THIRD;
}
}
// ... other states
public abstract StateMachine next();
// ... other methods
}
2014年3月27日 星期四
Running C/C++ on Android with NDK
需要準備的環境
- Eclipse + Android SDK: 基本的 Android 開發環境
- Android NDK: 讓 Android 能透過 JNI 去執行 C/C++ 語言的必要套件
- Eclipse NDK: Eclipse 的 plugin 套件,方便管理與建立 NDK 的專案
Work with: https://dl-ssl.google.com/android/eclipse/
安裝好之後要設定 Android NDK 的路徑:
Window -> Preferences -> Android -> NDK -> NDK Location: - Eclipse CDT: Eclipse 的 plugin 套件,可以在 Eclipse 上管理與開發 C/C++ 專案
Work with: http://download.eclipse.org/tools/cdt/releases/juno (For Juno)
Work with: http://download.eclipse.org/tools/cdt/releases/kepler (For Kepler) - Cygwin: 用來編譯 C/C++
Ref: http://blog.csdn.net/javatiger427/article/details/6115693
註2: CDT(C/C++ Development Tooling)
新建一個專案
http://www.pupuliao.info/2013/05/%E5%9C%A8eclipse%E9%80%8F%E9%81%8Ejni-%E8%B7%91cc-for-android-hello_world%E7%AF%87/
文中設定 Builder 的部分可略過,只是為了存檔的同時也能重新自動建置。
而且遇到有空白字元的路徑更為麻煩,可將文中 Arguments 的部分換成如下:
--login -c "cd /cygdrive/d/sample && rm -r obj && /cygdrive/c/Progra~1/Android/android-ndk-r9d/ndk-build"
另外,我們也可以透過按下小鎚子的圖示來手動建置。
除錯
除錯時要將 Project -> Properties -> C/C++ Build -> Builder Settings -> Build Command:
加上 ndk-build NDK_DEBUG=1,建置時才會產生除錯所需要的檔案。
在這之後可能會遇到兩個問題:
- 無法在 .c 或 .cpp 檔上設置中斷點?
Run -> Breakpoint Types -> C/C++ Breakpoints - 設完中斷點後,卻沒有停在中斷點上?
No symbol table is loaded. Use the "file" command.
由於 GDB debugger 需要一點時間運算,而 GDB 可能還沒載入 Library 的 Symbol,
如果中斷點設得太早可能會被忽略,
解決的辦法請參考:
http://www.codeproject.com/Articles/493043/Why-your-Android-NDK-breakpoints-might-fail-and-ho
2013年8月14日 星期三
"Java SE7 技術手冊" 讀後筆記
CH3 基礎與法
- 如果運算式中包括不同型態數值,則運算時以長度最長的型態為主,其他數值自動提昇 (Promote) 型態。
- 如果運算元都是不大於 int 的整數,則自動提升為 int 型態進行運算。
所以下方的例子將編譯失敗 (Type mismatch: cannot convert from int to short) :
short a = 2; short b = 3; short c = a + b; // Sol: short c = (short)a + b;
CH4 認識物件
-
Integer 實際上是使用 Integer.valueof() 來建立 Integer 實例,所以看看 Integer.java (可在 JDK 資料夾 src.zip 中的 java/lang
底下找到) ,會發現其在 -128 ~ 127 間有 cache 的機制。public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } - 使用 + 串接字串會產生新的 String 實例,所以不要將 + 用在重複性的串接場合,可用 StringBuilder (Note: 適用於 single thread,multithread 則用 StringBuffer) 來改善效能。
CH5 物件封裝
- 如果沒有宣告權限修飾的成員,只有在相同套件的類別中,才可以直接存取,也就是"套件範圍權限"。
CH7 介面與多型
- interface 的方法只能宣告為 public abstract (也可省略不寫),無須且不能有實作。
- Listener 常用 interface 來實作。
CH11 執行緒與並行 API
- 執行緒有可能在未經 notify()、interrupt() 或逾時情況下私自甦醒 (Spurious wakeup),
所以 wait() 一定要在條件成立的迴圈中執行。
2013年4月10日 星期三
Advanced Uses of Enum
常見的 Enum 用法大多如下:
其實 Enum 可以更好用,假如我們今天有個菜單分別有名稱和價錢兩個屬性,我們便可以建立
Enum 的 Constructor 使其可以輸入名稱和價錢。之後,還可以拿名稱和價錢來做一些運算,例
如格式化文字的輸出,只要 Override toString() 即可。
public enum EnumMenu{
APPLE,
BANANNA,
CHEESE
}
其實 Enum 可以更好用,假如我們今天有個菜單分別有名稱和價錢兩個屬性,我們便可以建立
Enum 的 Constructor 使其可以輸入名稱和價錢。之後,還可以拿名稱和價錢來做一些運算,例
如格式化文字的輸出,只要 Override toString() 即可。
public enum EnumMenu{
APPLE("Apple", 10),
BANANNA("Bananna", 20),
CHEESE("Cheese", 30);
private String name;
private int price;
private EnumMenu(String name, int price) {
this.name = name;
this.price = price;
}
public String toString(){
return "Name: " + name + ", Price: " + price;
}
}
// System.out.println(EnumMenu.APPLE); // Name: apple, Price: 10
2013年4月9日 星期二
Enable Intellisense for Eclipse
Intellisense 可以讓使用者在敲首字時即開始提示,Eclipse 預設雖然有開啟這項功能,
但只有當按下 . 的時候才有作用,否則必須要按 Alt + / 才會出現選單以供選擇。
但只有當按下 . 的時候才有作用,否則必須要按 Alt + / 才會出現選單以供選擇。
想要開啟如同 VS 首字開始自動提示的功能的話,步驟如下:
1. 工具列 Windows -> Preferences
2. 開啟對話視窗後 Java -> Editor -> Content Assist
3. 勾選 "Enable auto-activation" 的選項
Auto activation delay 為提示出現的延遲時間。
Auto activation triggers for Java 為 IDE 遇到何種字元會自動啟動提示,預設只有 dot,改成 .abcdefghijklmnopqrstuvwxyz(,
Auto activation triggers for Javadoc 在註解區塊中遇到何種字元會啟動提示,預設是 @ 及 #
改完後 Apply -> OK
1. 工具列 Windows -> Preferences
2. 開啟對話視窗後 Java -> Editor -> Content Assist
3. 勾選 "Enable auto-activation" 的選項
Auto activation delay 為提示出現的延遲時間。
Auto activation triggers for Java 為 IDE 遇到何種字元會自動啟動提示,預設只有 dot,改成 .abcdefghijklmnopqrstuvwxyz(,
Auto activation triggers for Javadoc 在註解區塊中遇到何種字元會啟動提示,預設是 @ 及 #
改完後 Apply -> OK
2013年4月2日 星期二
使用 Socket 前要注意的二三事
- 不應該在 UI thread 建立 Socket。(For Android)
- socket.isClosed() 只能判斷 local 端的 socket 是否被關閉了,無法判斷 remote 端的,
例如即使 Client 已關閉 socket,在 Server 端呼叫 isClosed() 還是會拿到 FALSE。
想判斷是否還可正常連線,就只能直接 read/write 看看,如果 read() 回傳 -1,就代
表連線可能已經中斷導致 Stream 也被關閉,再也拿不到資料 (EOF)。 - 當兩邊 Stream 建立時,一方的 read() 通常會被 block 住,但如果另一方的 Stream
突然被關閉,此時的 read() 再也不會被 block,而是不斷的回傳 -1 (EOF)。
2013年3月29日 星期五
Measure the display width of a string
我們常常會用 Graphics2D.drawString("Hello", 100, 100); 在元件上畫出字串,
若想要依字串畫出來的大小來決定其位置,可以先取得 FontMetrics 物件,
FontMetrics fm = getFontMetrics(font);
再透過 FontMetrics.getHeight() 和 fm.stringWidth(String) 即可拿到該字串的高和寬。
若想要依字串畫出來的大小來決定其位置,可以先取得 FontMetrics 物件,
FontMetrics fm = getFontMetrics(font);
再透過 FontMetrics.getHeight() 和 fm.stringWidth(String) 即可拿到該字串的高和寬。
Do not use Socket with DataInputStream
今天在寫的 socket 程式時,使用 DataInputStream/DataOutputStream 來傳遞資料,
發現用 DataInputStream 時,能夠一次讀到的 bytes 很少,每次都是 1448 bytes
(不知道怎麼算出來的?),讀的也很慢。試著改用 BufferedInputStream/BufferedOutputStream
來傳遞資料發現變快許多,而且每次能讀的的 bytes 也比較多,都是 1448 的整數倍,
1448, 2896(2x1448), 4344(3), 8688(6), 30408(21), 33304(23), 36200(25)... 等。
發現用 DataInputStream 時,能夠一次讀到的 bytes 很少,每次都是 1448 bytes
(不知道怎麼算出來的?),讀的也很慢。試著改用 BufferedInputStream/BufferedOutputStream
來傳遞資料發現變快許多,而且每次能讀的的 bytes 也比較多,都是 1448 的整數倍,
1448, 2896(2x1448), 4344(3), 8688(6), 30408(21), 33304(23), 36200(25)... 等。
2013年3月28日 星期四
new Socket 時發生 Exception
今天想寫一個 Android 的 Client 端將資料傳輸到 PC 的 Server 端。
我在 onCreate() 時去 new Socket(strIP, 27015) 卻發生 NullPointerException。
strIP 明明就不是 null pointer,傳進去後卻莫名變成 null 了。
在網路上也找不到相關的資料,索性試著將 new Socket 一行移至 OnClick(),
這時跑出了另一個 NetworkOnMainThreadException,於是讓我找到了相關的文章。
根據 Why Ice Cream Sandwich Crashes Your App 這篇文章的說明,Android 3.0 以上
不允許在 UI thread 裡做以下的運算:
我在 onCreate() 時去 new Socket(strIP, 27015) 卻發生 NullPointerException。
strIP 明明就不是 null pointer,傳進去後卻莫名變成 null 了。
在網路上也找不到相關的資料,索性試著將 new Socket 一行移至 OnClick(),
這時跑出了另一個 NetworkOnMainThreadException,於是讓我找到了相關的文章。
根據 Why Ice Cream Sandwich Crashes Your App 這篇文章的說明,Android 3.0 以上
不允許在 UI thread 裡做以下的運算:
- Opening a Socket connection (i.e. new Socket()).
- HTTP requests (i.e. HTTPClient and HTTPUrlConnection).
- Attempting to connect to a remote MySQL database.
- Downloading a file (i.e. Downloader.downloadFile()).
Debugging with Android SDK source code
之前已提過 [Eclipse] 對 Java SDK source code debug。
對於 Android SDK source code debug 也是一樣,問題是要如何取得 Android SDK
的 source code 呢? 對於 Android 4.0 之前需要用 Repro 和 Git 這類的工具將 source
抓下來,到了 4.0 之後不需要在這麼麻煩,直接在 Android SDK Manager 就可以
下載,下載完後在 Debug perspective 對該 process 按下滑鼠右鍵選擇
Edit Lookup Path... 設置對應路徑即可。
對於 Android SDK source code debug 也是一樣,問題是要如何取得 Android SDK
的 source code 呢? 對於 Android 4.0 之前需要用 Repro 和 Git 這類的工具將 source
抓下來,到了 4.0 之後不需要在這麼麻煩,直接在 Android SDK Manager 就可以
下載,下載完後在 Debug perspective 對該 process 按下滑鼠右鍵選擇
Edit Lookup Path... 設置對應路徑即可。
![]() |
| ▲ Android SDK Manager |
[Eclipse] 對 Java SDK source code debug
我們可以安裝 JRE 或 JDK 來開發 Java 程式,但若要看到 Java SDK 的 source code,
並針對其 Debug,我們就只能安裝 JDK 了。
只要在 Window → Preferences → Java → Installed JREs → Search.... 設置 JDK 所安裝的
路徑即可。如此一來便可透過 F3 或 Ctrl + 滑鼠左鍵看到定義 String 的 class 檔,而不會
有 "Source not found" 的訊息頁跑出來。
有 "Source not found" 的訊息頁跑出來。
2013年1月18日 星期五
2012年12月29日 星期六
Primitive type & Reference type
在 Java 裡,型別被分為兩大類 Primitive type 和 Reference type,
有八個型別屬於 Primitive type,分別是 boolean, char, byte, short, int, long, float, double,
其他如 String, Array 和使用者自定義的 class 則屬於 Reference type。
而兩者重要的差別在於,當變數被當作函式的參數傳遞時,
Primitive type 的值不因函式運算而改變。
Reference type 的值會因函式運算而改變 (除了 String 以外!)。
大多人會覺得那這不就是 C++ 中的 call by reference 嗎?
其實都是 call by value,因為 Java 不允許處理記憶體位置。
(詳見: http://openhome.cc/Gossip/JavaEssence/CallByValue.html)。
String 雖然是 Reference type,但在函式裡更改其值,並不影響外部變數的結果,
這是因為 str = "Hello" 等同於 str = new String("Hello"),str 指向了新的記憶體空間,
所以不會更動到原本的記憶體。
有八個型別屬於 Primitive type,分別是 boolean, char, byte, short, int, long, float, double,
其他如 String, Array 和使用者自定義的 class 則屬於 Reference type。
而兩者重要的差別在於,當變數被當作函式的參數傳遞時,
Primitive type 的值不因函式運算而改變。
Reference type 的值會因函式運算而改變 (除了 String 以外!)。
大多人會覺得那這不就是 C++ 中的 call by reference 嗎?
其實都是 call by value,因為 Java 不允許處理記憶體位置。
(詳見: http://openhome.cc/Gossip/JavaEssence/CallByValue.html)。
String 雖然是 Reference type,但在函式裡更改其值,並不影響外部變數的結果,
這是因為 str = "Hello" 等同於 str = new String("Hello"),str 指向了新的記憶體空間,
所以不會更動到原本的記憶體。
2012年12月18日 星期二
用 Java 讀取 HTTP 網頁內容
在 JDK 的 java.net 包中已經提供了訪問 HTTP 協定的基本功能:HttpURLConnection。
而 Apache 也提供了對應的 HttpClient 功能更為強大也更容易使用。
HttpURLConnection 與 HttpClient 的比較可參考這篇文章 :
http://superonion.iteye.com/blog/1545496
而下面是個完整可執行的程式碼,用來讀取 Apache 的網頁資訊 :
而 Apache 也提供了對應的 HttpClient 功能更為強大也更容易使用。
HttpURLConnection 與 HttpClient 的比較可參考這篇文章 :
http://superonion.iteye.com/blog/1545496
而下面是個完整可執行的程式碼,用來讀取 Apache 的網頁資訊 :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
// Using version 4.2.2
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
public class HttpClientSample{
public static void main(String[] args) throws ClientProtocolException, IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
// Prepare a request object
HttpGet httpget = new HttpGet("http://www.apache.org/");
// Execute the request
HttpResponse response = httpClient.execute(httpget);
// Examine the response status
System.out.println(response.getStatusLine());
// Get hold of the response entity
HttpEntity entity = response.getEntity();
System.out.println(entity.getContentType());
//System.out.println(EntityUtils.toString(entity));
// If the response does not enclose an entity, there is no need
// to worry about connection release
if (entity != null) {
InputStream instream = entity.getContent();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
// do something useful with the response
String str;
while (reader != null && (str = reader.readLine()) != null)
{
System.out.println(str);
}
} catch (IOException ex) {
// In case of an IOException the connection will be released
// back to the connection manager automatically
throw ex;
} catch (RuntimeException ex) {
// In case of an unexpected exception you may want to abort
// the HTTP request in order to shut down the underlying
// connection and release it back to the connection manager.
httpget.abort();
throw ex;
} finally {
// Closing the input stream will trigger connection release
instream.close();
}
}
}
}
2012年11月27日 星期二
安裝 Aptana Studio 3
Aptana Studio 3 是一套支援網頁開發的外掛程式,支援大部分的網頁語言編輯撰寫功能,
如 HTML、PHP、JavaScript、Rails、Python 等。而除了程式碼提示、自動完成與偵錯的功能,
也提供了一些程式碼的佈景主題,讓程式碼更容易閱讀。
在 Eclipse 安裝 Aptana Studio 3 的套件時,如果曾經裝過 PyDev 套件,
如 HTML、PHP、JavaScript、Rails、Python 等。而除了程式碼提示、自動完成與偵錯的功能,
也提供了一些程式碼的佈景主題,讓程式碼更容易閱讀。
在 Eclipse 安裝 Aptana Studio 3 的套件時,如果曾經裝過 PyDev 套件,
會出現和 Aptana 和 PyDev 相衝的錯誤訊息,因為 Aptana Studio 3 裡已包含 PyDev 套件,
所以可先移除 PyDev 套件再重新安裝一次即可。
在 2014.8.22 補充:
最近更新 Aptana 3.6 後,PyDev 在 theme 和 auto completion 上都變得怪怪的,
後來乾脆只裝 PyDev 3.6,自己改 PyDev Editor 的 Color 設定。
XML 則裝 Rinzo XML Editor 1.4: http://editorxml.sourceforge.net/updates/。
在 2014.8.22 補充:
最近更新 Aptana 3.6 後,PyDev 在 theme 和 auto completion 上都變得怪怪的,
後來乾脆只裝 PyDev 3.6,自己改 PyDev Editor 的 Color 設定。
XML 則裝 Rinzo XML Editor 1.4: http://editorxml.sourceforge.net/updates/。
訂閱:
文章 (Atom)


