List如何排序
List排序可以通過實現Comparable接口并且實現compareTo方法,或者傳入comparator去實現排序。
內存溢出/OOM是怎么回事?
內存溢出就是程序在運行的過程中,申請的內存超過了最大內存限制,導致JVM拋出OOM異常,這個叫內存溢出。
一般內存溢出有蠻多情況的,像是我之前的第一份實習不是要用java去做RPC自動化系統嘛。他本質就是java去做爬蟲,所以自己私底下做過一些練習,然后就遇到了一個情況就是某個網頁它指向的是下載某個文件,這個文件可能很大,就導致堆內存溢出。
我當時的解決方案是首先,通過它的url看下有沒有特定的后綴,像是.doc之類的,如果是的話這個url就不加入處理的隊列。其次就是通過httpURLConnectiongetContentLength()去加上限制,如果超過3MB,也是不把這個url加入處理的隊列。
當然只能說規避了一小部分,首先就是很多url都沒有像.doc這樣顯式的后綴的。其次就是很多HTT P Response其實都不設置contentLength的。
所以后續我記得還是手動設置了一個byte數組當作緩沖池,如果填滿了這個數組而且還有未讀完的數據的話,就放棄這個url。
那除了這種堆內存溢出之外的情況,還比較經常遇到的,可能寫算法經常就可以看到棧溢出。就是循環遞歸沒有寫好之類的。
內存溢出如何排查和解決?
至于排查的話,這個項目是沒有配普羅米修斯的,因為是我自己寫的demo嘛。如果有配普羅米修斯的話會簡單很多。那我們可以在啟動項目的時候設置一下,當他內存溢出的時候保存一個內存快照,一個指定的dump文件。然后用分析工具,譬如MAT去執行分析。一般它會幫你分析最大的對象是誰,次大的對象是誰等等。然后就可以通過這個對象的路徑,它是哪個包下面的,去定位到具體是哪段代碼導致的內存溢出。
提到這個就得說一句,這也是為什么我們啟動線程的時候最好命名的原因,像是如果沒有命名的話,可能是公用線程池的一個線程,或者tomcat的線程,他在排查的時候就沒有名字,只有數字序號之類的,排查起來就會麻煩一些。
那如果我們排查到是緩存沒有做好的原因,那就去考慮一下緩存的過期時間是不是沒有設置好,是不是可以放到redis里面之類的。從而去解決問題。
當然,其實我們應該內存達到60%左右就設置一下告警的。因為內存不斷升高,在它溢出之前它肯定不斷GC了,那GC的話又是很耗cpu的,就導致整個服務的響應都不是很好。最后內存溢出嚴重的話,整個服務應用可能都無響應了。甚至嚴重點的話,可能還會觸發操作系統的內存溢出,然后終端進程也被kill掉了。
而且就是剛剛提到的,保存dump文件本身也是會占用cpu的,也會占用磁盤啊之類的,不過一般就是cpu。所以要盡量挑業務沒有那么繁忙的時候。
內存升高的原因有很多啊,像是緩存使用不當、有很多突增的流量、或者內存泄漏都會導致內存升高,不及時處理的話就會導致內存溢出。
其實開發中經常碰到內存溢出的情況,特別是一開始整個服務的規模很小,沒有多少日活的話,代碼可能就寫得比較簡單,然后不想引入那么多中間件,可能緩存就隨便做了,監控也沒有。結果后來數據越來越多,然后別人或者說自己也忘了哪里寫了個緩存了,就導致內存溢出了。然后只有一個日志去排查就很費勁。