小猿作了兩年的c++,上個月居然被調到java項目,因而第一篇隨筆就想八一八java的內存優化。html
首先優化這種事,確定是應該放到最後去作的,不過在寫代碼的過程當中養成良好的習慣也是很重要的。在這裏先推薦一本書《編寫高質量代碼:改善Java程序的151個建議.秦小波》。html5
首先,在寫代碼的時候,儘可能少用對象,能用基本變量代替的就用基本變量,這點下面會舉例。java
其次,不少時候你想作一個功能,寫一段代碼,不是用時間換空間就是用空間換時間。要根據這個功能究竟是看中時間,仍是看中空間,常訪問到的必然是要放到內存裏的,可是是否是能夠進行壓縮這個也要看對效率是否有影響。c++
其餘的就很少說,相信各位都有本身的好習慣。app
主要想說說內存優化。工具
小猿如今作的項目須要解析大量數據保存起來,因此如何節省內存很是重要,否則導入一個100M的文件,就佔用1G的內存,客戶簡直要瘋掉了。優化
因而小猿進行第一步,排查內存的佔用狀況。ui
首先先使用的工具是jdk自帶的,jconsole.exe。spa
用這個軟件能夠清晰的看到你程序內存、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了,勿念…………………………