TAG | Java
Scaling Your Java EE Applications
Scaling Your Java EE Applications Part 2
SMP 和 Server Load balancing 要注意的地方
Eclipse 3.4 M7 – New and Noteworthy
其中我覺得最有用嘅係
Java compiler on multi-CPU machines
You should see faster Java compile times when using machines with multiple CPUs. The Eclipse Compiler for Java (aka "ecj") is now taking advantage of the multi-threading capability of multi-CPU machines. The full build of a Java project also takes advantage of this support.
最近推出的 Framework, library 的新版本,雖然知道,看到新聞,也讀過簡介,也參考過 sample code。
可是就沒有真正拿上手試過,寫過,用過。
總有一種,殺雞焉用牛刀的感覺而沒有在 small application 中使用它們。大型 application 的也很少要重新開發修改其 framework。
也會開始問理性地自己,為何要用新版?和舊版比較有甚麼特點?想過,仔細選擇過才去做。
難度我開始老了嗎。。。。。
上次寫完 Java, Garbage Collection與 Memory management 當中提到 AWT 和 Finalize 的關係,仔細一想後覺得大有文章,要再寫多少少。
有一少部新手入門看的書當中介紹的做法,和一部份 WYSIWYG GUI Editor 的做法,都是以 JDialog / JWindow 來實作自己的的視窗。可是根據 Swing 正確的 MVC design pattern 和 finalize 的關係來說,這是完全錯誤,而且可笑的,荒謬的做法。
如果只是為了即省幾行 code 或即省介紹每一節的功能,那就比較合理,但卻會教壞新手。
javax.swing.JDialog, javax.swing.JFrame 和 javax.swing.JWindow 都是 extends 了 java.awt.Dialog, java.awt.Frame 和 java.awt.Window 。本質上它們依然是一個 AWT 元件,只係在其上再加建 Swing 的 API 去支持運作。它們,依然是擁有 finalize method 的重元件(須要兩次 GC 才能清理)。
也就是你在自己 extends 了它們的 object 都自動成了重元件,令到任何在其中的 members 都無可避免地減低 GC 效率和增加記憶體使用量。而且,這根本就會令到你的物件本身的可重用性減低。
但很可惜在官方的 Tutorial Using Top-Level Containers 沒有提到這一點和它的重要性。
比較合理的做法是以 javax.swing.JComponent 或 javax.swing.JPanel 為基礎,而另外自行寫一組簡單的 function 來實現
frame=new JFrame();
frame.getContentPane().add(xxx);
而且,也為了 GC 優化,在確定 Window 不會重用(不會再執行 show() 或 setVisible(true);) 的地方(例如 void windowClosed(){…} ) 加上
frame.getContentPane().remove(xxx);
// 別忘了還有 Menu 和其他
,令它們和重元件 window 分離。
這樣一來,在 GC 的時候,它就能把 Windows 和 載有大量 data 的部份分開辦理,在 JPanel 當中存在/連結的大量 memory 能一口氣在第一次 GC 就能被清掉,而不是等 finalize 執行後的第二次 (甚至第三次, 第四次) 的 GC 才能被移除。
當然這樣的 GC 優化這對只會冇單一 Window 的 application 沒有特別意義的,也對 EXIT_ON_CLOSE 的 window 沒有意義。但能算是比較正規的做法。
我不喜歡 Swing,它實在太易令人犯錯而不自知。特別是那不 Thread-safe,但又難以 debug 的設定。
無論是 Java,英文,朋友,人際關係甚至係金錢管理。
古人話:『苦海無邊‥』呀唔係『學海無崖,唯勤是岸』都沒有錯
無論是甚麼人,學習甚麼也好,每學一件事,就會生出更多的問題要去解答,去再學習。不是你覺得已經足夠而放棄了學習,就是持續一直學下去,而永遠沒有學完了而停止的。
勤力的人,會比較快學得到他所需要的足夠的知識。但如果他停了下來放棄了 勤,就會慢慢被無情的浪再卷入學海當中。
最近,學習的進度好像學了下來。發覺自己雖然經學了不少,卻好像看到很多的地方要去學習改善。
我很疲倦而停下了腳步,我根本不能集中精神去學習。我心思都被某個人填滿--看吧,我原本沒有打算寫到她的,但還是這樣。
很多新手都以為, Java 和相比 C++,JVM 內置了 Garbage Collection 的功能就相等於 "我不用管" / "我可以寫少幾行 code",這種想法,是要不得的。
其實這也難怪,太多書本和教學寫得都不清楚,甚至錯誤百出。
不是為了吸引新手使用 Java,就是把它定義為進階深入的知識,或根本連作者本身都錯誤理解了。
其實無論是 Java , .NET 或其他附有 GC 或其他聲稱有 GC 功能的語言,也要自己面對資源回收的理
為垃圾而設想
Garbage Collection (垃圾回收) 能有效率地運作的大前提是,它要知道甚麼是垃圾,甚麼不垃圾。
理所當然的,當你手上還捉緊著它們,還有 Object 之間千絲萬縷的連結,你又叫 GC Engine 如何替你進行回收呢?
其他的還有 GC 的時機,策略,優化(避免劣化) 也是要由寫程式的人來想。
別忘了它們的手足
GC 本來就只能替你回收記憶體,可是你不要忘了除了記憶體,你還有別的垃圾。IO Handle, native code 的 pointer 或其他向 OS / Hardware 要來的資源 。GC Engine 是不知道如何釋放/回收它們的,GC 能做到的只是告訴你:『我看到它上面有條便條,它要我在回收之前通知你,記得有其他的事情要做』---也就是 finalize method。
當 GC engine 看到將要回收的 Object 上有 finalize method,則會把它們放到一邊,經由獨立的 Finalizer Thread 執行。而你要做的,就是記得在 finalize 內把自己用到的 sub-process / native pointer / windows handle / file handle 經由 JNI 方法自己放掉。正如在 C 當中 delete pointer 之前要把子內容清掉一樣。
可幸地, JDK 內所有一般性會使用 native resource 的 Object 都已實作了 finalize,你在正常情況下都不必為它們底層的 File Handle, Socket, GUI Handle, pointer…. 等等太過粗心。不過你還是要注意和小心的!
你應該知道 SWT / Swing 和 AWT 吧!我以前讀 SWT 介紹的時候都不了解這一小句『SWT doesn’t use the Java garbage collector….』當時我看不懂,近年才有所覺悟。它所說的,不是指 Java 中Object 記憶體的回收,而是指不等待不使用 GC 的 Finallizer 來回收 GUI Handler。 先說一點歷史,當年 AWT 設計上最失敗的地方不是其 heavy-weight (這只是 Sun 用來騙人的術語),也不是 GUI 的 cross-platform 問題。而是其而是其設計高估 GC 的能力 Finalizer Thread 的速度。 finalize 最大的多點是所有實現了它的 object 和它的子部件都至才要經過兩次 GC 才能被清掉,基本上所有使用了 AWT 的 Java Process 的 GC 都被劣化(使用 AWT 的大前提是你不應 extends 任何 AWT 元件)。而且 OS 能用的 GUI handle 數目是有限的,可是 AWT 就喜歡拿了一堆 Handle 不放手(還沒有 finalize 掉),令到整個 OS out-of-resource 的機會大大提高。
Swing 就是應用了 light-weight (另一個騙人的術語) 的想法,減少向 OS 要求 resource,把 GUI 放入自己管理的部份。SWING 自行產生,管理,繪畫,事件,消除。(怎麼看都是把原本 OS 做的事搶來自己做,根本是更加重,更加 heavy-weight 才對) 來達到多重目的。 LookAndFeel 是其中最沒有用最浪費,郤又最多人掛在口邊的的。
而 SWT 的想法就是:『好吧,我知道它們是何時成為垃圾,就由我來把它回收吧。』
很簡單,很易了解,其實也只是要求 Progarmmer 去做他們本來就應該要做的工作。
GC 不只是 Garbage Collection
上文不是提到 GC 是回收記憶體中的垃圾和其他垃圾嗎?為甚麼又說它不是垃圾回收呢?
的確,原本的 GC 的用意 (包括 Java / .NET / C++ 和其他) 很可能根本只是垃圾回收。可是把它套用在近代的 JVM 上就有點太過小看 GC 了。GC 的另一樣重要的價值是自動化的記憶體管理。簡單來說,就是能否善用空間的能力。
記憶體管理大概可以被分為:配置,釋放,重置,定位等等。
根據支持者的研究文件指出(忘了出處),老舊的 C/C++ 當中的 配置/釋放記憶體雖然每次都很快,但卻是 stop-the-world 的動作,效能算起來會和有 overhead 的 Java 差不多,甚至比 Java 差。
另外 GC 能避免 memory fragment 。fragment 的出現是因為程式每次向OS 要求 memory 都是以 page 為單位的,反復的配置/釋放會減低 page 真正需要使用的密度。JVM GC 在執行的時候,很多時候也會把 Object 的本體移來移去(e.g. Generational GC)。也是能把 2/5 + 2/5 + 1/5 整合為一個 5/5 的時機。VM 理論上和部份的實作上是做得到把常用的,連著使用的 object 放在一起,而把不太相關的,很有機會被垃圾掉了又放在另一個 page 內,而直接減少底層執行指令的負擔。例是說 String 本身和內在的 char[] 經常放在一起,減少要在多個不同的 page 讀寫的機會。
GC 它能做到的,它替你做到的,都比你想的多;但你也需要寫 GC friendly 的程式才行。
InfoQ: Lucene 2.3:大幅提升索引性能,新增機器學習項目
Ingersoll認為這次的版本中最大的變化是新的索引算法,它使用了新的in-memory模型來達到大幅的速度提升。據Ingersoll 說,單單是把Lucene 2.2 JAR換成Lucene 2.3 JAR就能在某些測試中把索引性能提速500%。其他改變還包括:
- 改進的索引管理——以前在索引過程中,當合併內部索引文件時偶爾會出現長時間的停頓,現在已經消滅了這種現象。另外現在也更容易實現其他途徑去管理索引過程。
- 對象池——
Document、Field和Token的實例現在可在索引分析中重用,因此不但提升了分析的速度,還減少了索引過程中的內存分配次數。- 重新打開IndexReader ——重新打開一個IndexReader去捕捉索引中最新的變化,這個操作的速度現在也更快了,新的reopen()方法只會加載那些變更過的索引片斷,而不是重新加載完整的索引。
- 更簡易的IndexWriter微調——
setMaxBufferedDocs已被更直觀的setRAMBufferSizeMB所取代。另外,2.3的目標是只需通過文件替換就能換下2.2,完全不需要重新編譯。這裡是完整的更新說明。
