java記憶體最佳化牛刀小試

來源:互聯網
上載者:User

標籤:

  小猿做了兩年的c++,上個月竟然被調到java項目,於是第一篇隨筆就想八一八java的記憶體最佳化。

  首先最佳化這種事,肯定是應該放到最後去做的,不過在寫代碼的過程中養成良好的習慣也是很重要的。在這裡先推薦一本書《編寫高品質代碼:改善Java程式的151個建議.秦小波》。

  首先,在寫代碼的時候,盡量少用對象,能用基本變數代替的就用基本變數,這點下面會舉例。

  其次,很多時候你想做一個功能,寫一段代碼,不是用時間換空間就是用空間換時間。要根據這個功能到底是看中時間,還是看中空間,常訪問到的必然是要放到記憶體裡的,但是是不是可以進行壓縮這個也要看對效率是否有影響。

  其他的就不多說,相信各位都有自己的好習慣。

  主要想說說記憶體最佳化。

  小猿現在做的項目需要解析大量資料儲存起來,所以如何節省記憶體非常重要,不然匯入一個100M的檔案,就佔用1G的記憶體,客戶簡直要瘋掉了。

  於是小猿進行第一步,排查記憶體的佔用情況。

  首先先使用的工具是jdk內建的,jconsole.exe。

  用這個軟體可以清晰的看到你程式記憶體、CPU、線程的情況。

  剛開始小猿發現明明自己程式堆使用記憶體量沒有那麼大啊,怎麼全部加起來和工作管理員的不一致!再細觀察之,程式的eden space佔用量很小。原來是沒有設定eden space的參數,這個要到啟動設定檔去設定:-Xmn,-XX:NewSize,-XX:MaxNewSize,-XX:NewRatio這些項都可以根據自己的需要去設定。

  因為如果沒有強制變數直接申請在old gen,變數是先申請在eden gen的,然後經過gc之後,如果這個變數倖存下來,就進入survivor區,然後再經過幾次gc,變數就存在old gen區了。

  事實上程式啟動穩定之後,可能大部分變數都已經到了old gen區去了,如果你的eden區記憶體配置過大,總量減去survivor減去eden之後剩下的old區就會不夠用了,這個時候虛擬機器幹什麼呢,虛擬機器會自動根據你設定的-Xms和-Xmx去擴容,於是你其實虛擬機器獲得的系統記憶體裡有很多是空閑記憶體,造成工作管理員裡看到的記憶體比你實際使用的大得多。

  於是小猿第一步調好了啟動參數,記憶體果珍降了一些,但其實這是假象,虛擬機器裡實際佔用的記憶體還是沒有變。

  小猿想知道更詳細的記憶體使用量,這就需要MemoryAnalyzer這個工具了,但是使用這個工具前,得產生程式的dump檔案,天哪我竟然百度出來的方法有利用增加啟動參數+HeapDumpOnOutOfMemoryError並且手動增加異常OutOfMemory來產生dump檔案。

  好吧小猿異常出來了,機子down掉了,好心塞。

  終於找到了好的方法,其實jdk內建的jconsole就可以產生的。

  在MBean->com.sun.management->HotSpotDiagnostic->操作->dumpHeap,把p0的值改成你產生dump檔案的路徑,點dumpHeap就可以。不過dump檔案的尾碼可不是dump!!!是hprof!!!

  產生之後,用MemoryAnalyzer開啟,leak Suspects之後,將會看到一個神奇的餅圖。裡面顯示的就是當前哪些instance佔用多少記憶體,有個details,點之。

  話說打不開MemoryAnalyze的孩紙你們jdk安了麼,java環境變數都配好了麼。

  看到詳細的記憶體佔用資訊,有多少個object等等。

  小猿這下終於發現可以最佳化的地方了。

  之前就對java的String心存怨念,這下怨念更深了,就是之前的那句,能用基本類型就用基本類型。

  小猿發現,有100000個String的object,還有100000個char[]的object。

  好吧,你用String存一個字串,其實是用他裡邊的char存字串,然後他自己還內建了各種親戚。

  你存一個“0”,String給你的對象大小可是比1Byte大得多!

  所以你可以調String的toCharArray()方法轉成char[]儲存。

  這裡再八一八什麼時候用String,什麼時候用StringBuffer,什麼時候用char。

  其實定義一個常用的常量字串用String那是極好的。

  比如

  String strTemp = “01”;

  String strTemp2 = “01”;

  這樣定義的話,strTemp和strTemp2實際上是共用了一個對象,只不過這個對象的引用是2!

  所以這樣定義10000000000個也只是佔了一個String對象,這是String特有的常量池。

  那為什麼還要用StringBuffer和StringBuild呢?

  因為StringBuffer和StringBuild的append比String的+要好!

  而且String本身設計的時候就是按常量去設計的,而StringBuffer和StringBuild才是真正可改變的字串。

  但是如果程式要儲存大量的沒有規則的字串,這個時候就建議轉成char來存。

  這隻是字串類型,其他的int等也是這樣的原則,盡量用基本變數儲存。

  縱觀高大上的java,宣稱沒有記憶體泄露的java,如果我們使用不當,是會造成記憶體浪費的。

  雖然退出程式的那一刻記憶體都會被正確的釋放掉,但是我們有時候更關心運行中的記憶體使用量情況。

  只要一個變數的引用計數不為0,gc就無法回收他,也許你這個object暫時沒用了,卻把他加到一個到程式結束才能被釋放的arraylist裡去,那這塊記憶體在運行中就被浪費掉了。

  java是不存在記憶體泄露,但是釋放的時機也很重要,一個對象對我們來說其實沒用了,卻被不小心把這個對象的鑰匙借給了一個生命週期比他長的對象,對我們來說就是記憶體泄露。

  可以好好的看看MemoryAnalyze,分析下現在存在的對象,是不是真的都有用,如果有無用的,一定是被哪裡引用了。

  小猿終於完成了第一篇java的隨筆。java速成一個月之後,下個月就要轉戰html5了,勿念…………………………

 

java記憶體最佳化牛刀小試

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.