總覽
Java有許多可能很慢的領域。 但是,對于每個問題都有解決方案。 許多解決方案/黑客都需要解決Java的保護問題,但是如果您需要低水平的性能,還是可以的。
Java使高級編程變得更簡單容易,但代價是使低級編程變得更加困難。 幸運的是,大多數應用程序都遵循經驗法則,即您將90%的時間花費在10%的代碼中。 這意味著您有90%的時間狀況良好,而有10%的時間狀況較差。 ;)
這讓我想知道為什么對于大多數項目,您會用C / C ++編寫超過10%的代碼。 在某些項目中,C / C ++是唯一明智的解決方案,但是我懷疑大多數C / C ++項目都可以通過使用Java之類的高級語言來提高生產力。
獲得類似C的性能的一種方法是通過JNI將C用于代碼的關鍵部分。 如果要避免使用C或JNI,仍然可以通過多種方法獲得所需的性能。
注意:這些建議大多數僅適用于獨立應用程序,而不適用于applet。
注意2:使用風險自負。 您可能需要測試使用低級Java時通常不需要擔心的極端情況。
快速陣列訪問
Java可能較慢的一個方面是數組訪問。 這是因為它隱式地進行邊界檢查。 JVM足夠聰明,可以通過檢查第一個和最后一個元素來優化循環檢查,但這并不總是適用。
一種解決方法是使用Unsafe類(該類僅在某些JVM上可用,而OpenJDK JVM才可用)。該類為每種基本類型都具有getXxxx()和setXxxx(),并允許您直接訪問對象,數組或直接內存,其中您必須進行邊界檢查。 在本機代碼中,這些被編譯為單個機器代碼指令。 還有一個getObject(),setObject()方法,但是我懷疑它們不能提供很多性能改進(在您訪問對象時也是如此)
您可以通過下載OpenJDK的調試版本并獲取其打印已編譯的本機代碼來檢查為方法生成的本機代碼。
任意內存訪問
您可以再次使用Unsafe類進行任意訪問,但是“更友好”的方法是使用DirectByteBuffer并根據需要更改其地址和限制(通過反射或通過JNI)。這將為您提供一個Buffer,它指向一個隨機區域。內存,例如設備緩沖區。
使用更少的內存
這已不再是一個問題。 一臺16 GB的服務器售價為1000美元,一臺1 TB的服務器售價約為7萬美元。
但是,緩存仍然是一種溢價,對于某些應用程序而言,它值得減少內存消耗。 一個簡單的事情是使用Trove ,它可以有效地支持集合中的原語。 如果數據表很大,則可以按列而不是按行存儲數據(如果有很多行數據和幾列數據)。 如果您要按字段掃描數據但不需要所有字段,則可以改善緩存行為。
您還可以使用直接存儲器按需要存儲數據。 這就是BigMemory庫所使用的。
基于流的IO速度很慢,NIO很難使用
如何利用您的兩全其美? 在NIO中使用阻塞IO(這是通道的默認設置)除非需要選擇器,否則不要使用選擇器。 在許多情況下,它們只會增加復雜性。 大多數系統可以有效處理1K-10K線程。 如果您需要更多的連接,請購買另一臺服務器,一臺便宜的服務器大約需要500美元。
快速高效的字符串
Java 6 update 21具有選項-XX:+ UseCompressedStrings,對于不需要16位字符的字符串,可以使用byte []代替char []。 對于許多應用程序,這可以節省內存,但速度較慢。 (5%-10%)
相反,您可以使用自己的Text類型來包裝byte [],或者從ByteBuffer,CharBuffer中獲取文本數據或使用Unsafe。
更快的啟動時間
當您加載許多腫的庫時,Java的啟動時間往往很慢。 如果這確實是一個問題,那么您加載較少的庫。 無論如何,將它們保持在最低水平是一個好習慣。 這樣做,您的啟動時間將為幾秒鐘(不及C快,但可能足夠快)
更少的GC暫停
大多數Java庫都是自由創建對象的,通常這不是問題。
但是,這并不意味著您不能預先分配對象,不能使用直接字節緩沖區和對象回收技術來最大程度地減少對象的創建。 通過增加Eden大小,您可以擁有很少使用GC的應用程序。 您甚至可以將其每天減少到一個GC(例如按計劃的通宵工作)
參考: 如何從Vanilla Java的 JCG合作伙伴 Peter Lawrey 獲得Java的C類性能 。
- Java中的低GC:使用原語而不是包裝器
- 每個程序員都應該知道的事情
- 正確記錄應用程序的10個技巧
- 軟件設計法則
- Java最佳實踐系列
- 生存在狂野西部開發過程中的9條提示
翻譯自: https://www.javacodegeeks.com/2011/07/how-to-get-c-like-performance-in-java.html