1. 程式人生 > 其它 >暴力求最大子陣列

暴力求最大子陣列

https://zhuanlan.zhihu.com/p/573662668

效能分析

在系統層面能夠影響應用效能的一般包括三個因素:CPU、記憶體和IO,可以從這三方面進行程式的效能瓶頸分析。

1. CPU分析

當程式響應變慢的時候,首先使用top、vmstat、ps等命令檢視系統的cpu使用率是否有異常,從而可以判斷出是否是cpu繁忙造成的效能問題。

cpu繁忙的原因有以下幾個:

  • 執行緒中有無限空迴圈、無阻塞、正則匹配或者單純的計算
  • 發生了頻繁的gc
  • 多執行緒的上下文切換

CPU調優

  • 不要存在一直執行的執行緒(無限while迴圈),可以使用sleep休眠一段時間。這種情況普遍存在於一些pull方式消費資料的場景下,當一次pull沒有拿到資料的時候建議sleep一下,再做下一次pull。
  • 輪詢的時候可以使用wait/notify機制
  • 避免迴圈、正則表示式匹配、計算過多,包括使用String的format、split、replace方法(可以使用apache的commons-lang裡的StringUtils對應的方法),使用正則去判斷郵箱格式(有時候會造成死迴圈)、序列/反序列化等。
  • 結合jvm和程式碼,避免產生頻繁的gc,尤其是full GC。

使用多執行緒的時候,還需要注意以下幾點:

  • 使用執行緒池,減少執行緒數以及執行緒的切換
  • 多執行緒對於鎖的競爭可以考慮減小鎖的粒度(使用ReetrantLock)、拆分鎖(類似ConcurrentHashMap分bucket上鎖), 或者使用CAS、ThreadLocal、不可變物件等無鎖技術。此外,多執行緒程式碼的編寫最好使用jdk提供的併發包、Executors框架以及ForkJoin等,此外Discuptor和Actor在合適的場景也可以使用。

2.記憶體分析

對Java應用來說,記憶體主要是由堆外記憶體和堆內記憶體組成。

  • 建立的物件:這個是儲存在堆中的,需要控制好物件的數量和大小,尤其是大的物件很容易進入老年代
  • 全域性集合:全域性集合通常是生命週期比較長的,因此需要特別注意全域性集合的使用
  • 快取:快取選用的資料結構不同,會很大程式影響記憶體的大小和gc
  • ClassLoader:主要是動態載入類容易造成永久代記憶體不足
  • 多執行緒:執行緒分配會佔用本地記憶體,過多的執行緒也會造成記憶體不足

排查堆記憶體問題的常用工具是jmap,是jdk自帶的。一些常用用法如下:

  • 檢視jvm記憶體使用狀況:jmap -heap
  • 檢視jvm記憶體存活的物件:jmap -histo:live
  • 把heap裡所有物件都dump下來,無論物件是死是活:jmap -dump:format=b,file=xxx.hprof
  • 先做一次full GC,再dump,只包含仍然存活的物件資訊:jmap -dump:format=b,live,file=xxx.hprof

記憶體調優

記憶體的調優主要就是對jvm的調優。

  • 合理設定各個代的大小。避免新生代設定過小(不夠用,經常minor gc並進入老年代)以及過大(會產生碎片),同樣也要避免Survivor設定過大和過小。
  • 選擇合適的GC策略。需要根據不同的場景選擇合適的gc策略。這裡需要說的是,cms並非全能的。除非特別需要再設定,畢竟cms的新生代回收策略parnew並非最快的,且cms會產生碎片。此外,G1直到jdk8的出現也並沒有得到廣泛應用,並不建議使用。
  • jvm啟動引數配置-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:[log_path],以記錄gc日誌,便於排查問題。

程式碼上,也需要注意:

  • 避免儲存重複的String物件,同時也需要小心String.subString()與String.intern()的使用
  • 儘量不要使用finalizer
  • 釋放不必要的引用:ThreadLocal使用完記得釋放以防止記憶體洩漏,各種stream使用完也記得close。
  • 使用物件池避免無節制建立物件,造成頻繁gc。但不要隨便使用物件池,除非像連線池、執行緒池這種初始化/建立資源消耗較大的場景,
  • 快取失效演算法,可以考慮使用SoftReference、WeakReference儲存快取物件
  • 謹慎熱部署/載入的使用,尤其是動態載入類等

3.IO分析

通常與應用效能相關的包括:檔案IO和網路IO。

  • 檔案IO可以使用系統工具pidstat、iostat、vmstat來檢視io的狀況。這裡可以看一張使用vmstat的結果圖。
  • 網路IO檢視網路io狀況,一般使用的是netstat工具。可以檢視所有連線的狀況、數目、埠資訊等。例如:當time_wait或者close_wait連線過多時,會影響應用的相應速度。

IO調優

檔案IO上需要注意:

  • 考慮使用非同步寫入代替同步寫入,可以借鑑redis的aof機制。
  • 利用快取,減少隨機讀
  • 儘量批量寫入,減少io次數和定址
  • 使用資料庫代替檔案儲存

網路IO上需要注意:

  • 和檔案IO類似,使用非同步IO、多路複用IO/事件驅動IO代替同步阻塞IO
  • 批量進行網路IO,減少IO次數
  • 使用快取,減少對網路資料的讀取
  • 使用協程: Quasar