StackOverflowError
前段時間一個同事給了個錯誤。看完整個log信息,感覺很懵。相信很多人更熟悉的是另一個錯誤,即OutOfMemoryError。
Caused by: java.lang.StackOverflowError
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
at oracle.net.ns.DataPacket.send(DataPacket.java:209)
at oracle.net.ns.NetOutputStream.write(NetOutputStream.java:180)
at oracle.jdbc.driver.T4CSocketOutputStreamWrapper.flush(T4CSocketOutputStreamWrapper.java:98)
at oracle.jdbc.driver.T4CSocketOutputStreamWrapper.flush(T4CSocketOutputStreamWrapper.java:91)
OutOfMemoryError
簡單來說就是年內存溢出。在操作系統層時,當分配內存時,若不夠也會類似錯誤。不過在這裏分兩類:
1. JVM中爲對象分配內存時,JVM內存區域溢出。
2. JVM中各個區域擴展空間時,系統內存不足。
對於第一種,如java.lang.OutOfMemoryError java heap space 就是堆空間不足。OutOfMemoryError PremGen space時,說明是方法區溢出。
JVM內存模型
相信很多人對這個圖很眼熟。
注意:
灰色區域:線程共享
白色區域:各線程私有
程序計數器
是一塊很小的內存空間。用於指示當前線程所執行的字節碼的行號(執行Native方法時,爲空)。比如控制分支、循環、跳轉、異常處理、線程恢復等。之所以說“線程私有”,是因爲每個線程都需要一個獨立的程序計數器來保證切換線程後能恢復到正確的位置。
堆
堆是JVM裏面內存最大的一塊區域。幾乎所有的對象實例都在這裏分配內存。當無法分配內存給實例時,拋出OutOfMemoryError。當然堆的大小也可以擴展,如果擴展不了也會拋出OutOfMemoryError。
方法區
從名字就知道,方法區用於存放已被虛擬機加載的類信息、常量、靜態變量等。也就是我們俗稱的“永久代”。當然這只是相對的,比如也會存在類卸載等。另外,方法區無法滿足內存分配需求時,也會拋出OutOfMemoryError。
值得說的是,JVM中說的運行時常量池,比如字符串池等也是這個區域的一部分。
虛擬機棧
虛擬機棧用於執行Java方法,因此很容易知道它是線程私有的。JVM文檔裏:每個方法被執行的時候都會同時創建一個棧幀用於存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。因此每個方法執行時,都會有進棧和出棧。
平時,我們遇到的StackOverflowError異常,一般都是發生在這個區域。表示線程請求的棧深度大於虛擬機所允許的深度。當然如果該區域擴展失敗時也會拋出OutOfMemoryError。
本地方法棧
該區域跟Java虛擬機棧作用一樣,不過執行的是Java中Native方法。也會StackOverflowError和OutOfMemoryError。
GC
垃圾回收有多種算法:標記-清除算法、複製算法和標記整理算法。每個算法怎麼操作的網上都有一堆資料。這裏不解釋了。
JDK Tools
其實JDK自帶了很多強大的工具,位於%JAVA_HOME%\bin 下,因此使用的時候要打開cmd然後進去該目錄。
jps
jps -l
這樣就可以查看本地所有java進程pid及名字
比如,本地weblogic的進程pid現在是 32020.
jstat
通過該命令可以查看某個進程的情況。
jstat -gc 32020 300 20
注意:這裏 32020 是上邊查到的pid,jstack
該命令可以查看當前進程的棧情況
jstack -l 32020
JConsole
到了我們的工具重頭戲了。上邊提到的工具一方面都是 unsupport的,另一方面可讀性都不是很好,且都是查看本地JVM。jconsole既能monitor本地JVM也能monitor遠程JVM。
打開jconsole後,它會列出所有本地可用的JVM進程,選擇一個即可連接。另外也可以指定host:port 去連接遠程的JVM。
連接我本地的weblogic效果如下:
切換到Memory tab即可查看各個JVM內存區域的使用情況。另外也可以點擊 "Perform GC",讓JVM執行GC。這樣就可以判斷哪個內存區域在垃圾回收後依舊出現大量佔用。
Monitor Tomcat
在tomcat中的目錄中,打開bin/catalina.bat文件,在以下位置加上一句。
set JAVA_OPTS=-Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
打開JConsole後,輸入host,然後加上邊設的8999即可。
Visualvm
Visualvm(多合一故障處理工具)可以說是JConsole的升級版,而且還可以安裝一些插件,感覺更好用些。至少不用再去jre\lib\management 下面配置一些密碼了。visualvm也是位於該目錄下,雙擊jvisualvm.exe 即可打開。
JMeter
Apache JMeter是Apache組織開發的基於Java的壓力測試工具。可以去官網下載,解壓即可使用。
雙擊運行apache-jmeter-4.0\bin\jmeter.bat 即可啓動。
使用JMeter分三步:創建請求線程組,設置監聽器,執行請求並查看結果。
創建請求線程組
在“Test Plan”(測試計劃)上右鍵,創建一個 Thread Group
配置Thread Group的請求參數,並保存。
添加請求:這裏我是測試一個Restful,使用HTTP Request。
同時指定要測試的URL,需要的話也可以添加參數:
設置監聽器
執行請求並查看結果
點擊執行,然後就可以查看測試結果了。