自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

手把手教你使用JConsole

開發(fā) 前端
我們通過線程 tab 看到了線程的 Runnable、WAITING 以及 BLOCKED 3 種狀態(tài)。要特別注意區(qū)分 WAITING 和 BLOCKED 狀態(tài),簡(jiǎn)單來說 WAITING 和我們的 wait 方法有關(guān),而 BLOCKED 則和鎖有關(guān)。

目前市面上有多種 JVM 監(jiān)控工具供我們選擇,其中 JConsole 可以算是 JVM 監(jiān)控始祖了,從 JDK1.5 就開始引入。最關(guān)鍵的是 JConsole 是 JDK 官方自帶的控制臺(tái),在一些特殊環(huán)境,比如網(wǎng)絡(luò)不通的情況下,可能是你唯一可以使用的圖形化監(jiān)控工具了。因此我們有必要對(duì) JConsole 的使用方法做一個(gè)了解。并且對(duì)大多數(shù)監(jiān)控需求來說,JConsole 完全可以滿足我們的需要,今天我們就來看看一直被我們低估的 JConsole 到底如何使用。

首先我們先找到 JDK/bin 目錄下的 JConsole 命令,啟動(dòng) JConsole。下圖是我本機(jī)的 JConsole 啟動(dòng)界面。

圖片圖片

我們可以看到,JConsole 啟動(dòng)時(shí)在本地進(jìn)程中會(huì)列出所有 JVM 進(jìn)程 PID,相當(dāng)于可視化的 jps 命令。我本機(jī)現(xiàn)在運(yùn)行的幾個(gè)虛擬機(jī)進(jìn)程分別是 StudyDemoApplication、JConsole、jps 和 idea。現(xiàn)在我們雙擊 StudyDemoApplication 進(jìn)去看看。

進(jìn)入具體的進(jìn)程后,我們會(huì)看到幾個(gè) tab 選項(xiàng),其中概覽是我們需要重點(diǎn)關(guān)注的,概覽的內(nèi)容比較直觀,包括了我們最關(guān)心的堆內(nèi)存使用量、線程、類、CPU 使用情況這四個(gè)信息的曲線圖。除了概覽,被高頻使用的還有內(nèi)存和線程 2 個(gè) tab,下面我們分別介紹它們。

圖片圖片

內(nèi)存

我們先來看內(nèi)存 tab 吧。 內(nèi)存這個(gè) tab 用于監(jiān)視虛擬機(jī)堆內(nèi)存、非堆內(nèi)存、內(nèi)存池等的變化趨勢(shì)。可以通過圖表下拉框去選擇要監(jiān)視的信息,還可以選擇時(shí)間范圍。

之前我在《 如何 使用 JVM 工具排查線上問題》課中介紹過 jstat 的使用方法,JConsole 內(nèi)部集成了 jstat,圖形化的展示讓內(nèi)存信息更直觀。注意,這里的下拉列表和你使用的垃圾收集器有關(guān),比如默認(rèn)使用的是 Parallel Scavenge 垃圾收集器,縮寫就是 PS,因此會(huì)看到 PS 前綴。

圖片

我們通過一個(gè)具體的例子來感受一下。下面這段代碼每隔 30 毫秒都會(huì)往 list 追加大小為 64KB 的 OOMObject 對(duì)象,此時(shí)我的堆設(shè)置是 100MB。

public class TestMemoryMonitor {
    /**
     * 存占位符對(duì)象,一個(gè) OOMObject 大約占 64KB
     */
    staticclass OOMObject{
        publicbyte[] placeholder = newbyte[64 * 1024];
    }
    public static void fillHeap(int num) throws InterruptedException {
        List<OOMObject> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            //稍作延時(shí),令監(jiān)視曲線的變化更加明顯
            Thread.sleep(30);
            list.add(new OOMObject());
        }
        System.gc();
    }
    public static void main(String[] args) throws Exception {
        fillHeap(3000);
    }
 }

程序運(yùn)行后,連接一下運(yùn)行的 PID。在圖表列表中,選擇 內(nèi)存池“PS Eden Space”,我們一起來看下內(nèi)存的使用情況。

圖片圖片

我們看到 for 循環(huán) 1000 次執(zhí)行完成后,形成了一個(gè)折線狀的圖。你可以看一下,右下角柱狀圖中的【堆】區(qū)域有 3 個(gè)柱狀圖,從左到右依次是“PS Old Gen”、“PS Eden Space”和“PS Survivor Space”。

我們可以看到在開始往堆填充數(shù)據(jù)時(shí),出現(xiàn)了一條勻速向上的、趨近直線的折線。每隔 30 毫秒停止填充,曲線急劇下降,周而復(fù)始直至完成。我們?cè)賮砜纯磮D表右下角的柱狀圖,當(dāng) for 循環(huán)執(zhí)行結(jié)束,我們執(zhí)行 System.gc() 后,Eden 和 Survivor 區(qū)中的空間幾乎都被釋放了,但是老年代的已使用空間還在緩慢增長(zhǎng)。

顯然,我們的對(duì)象并沒有真正被釋放,而是在 System.gc() 發(fā)生之后進(jìn)入了老年代。在我們的代碼中 List 在整個(gè) fillHeap 方法中都是有效的,當(dāng)我們執(zhí)行 System.gc() 時(shí)并沒有離開 List 的作用域。

如果這個(gè)時(shí)候想要回收全部?jī)?nèi)存該怎么辦呢?你可以嘗試一下,把 System.gc() 放到 fillHeap 方法外運(yùn)行一下試試,顯然由于此時(shí) fillHeap 方法已經(jīng)退出,List 不再有效,隨時(shí)可以被回收。

在實(shí)驗(yàn)的時(shí)候要注意 System.gc() 并不一定總是有效的。這是因?yàn)?System.gc() 并不是強(qiáng)制執(zhí)行的,而只是通知 JVM 快去回收對(duì)象,具體什么時(shí)候執(zhí)行 JVM 說了算。這種感覺就像你在餐廳點(diǎn)菜,你覺得上菜比較慢,你就會(huì)催促服務(wù)員,但是催促服務(wù)員并不意味著立刻就會(huì)上菜,具體菜什么時(shí)候做好還是廚師說了算。

線程

接下來,我們聊聊另一個(gè)重要的 tab——線程。我在《 如何 使用 JVM 工具排查線上問題》課程中介紹過 jstack 命令,線程 tab 的功能基本和 jstack 命令一致。我們知道線程出現(xiàn)阻塞的原因包括: 等待外部資源、長(zhǎng)時(shí)間執(zhí)行的循環(huán)、鎖。

下面我們通過一段代碼來觀測(cè)常見的線程阻塞例子。

public static void createBusyThread(){
    Thread test1= new Thread(()->{while(true);});
    test1. start();
}
public static void createLockThread (final Object lock) {
    Thread test2= new Thread (()->{
    synchronized(lock){
                try{
                    lock. wait();
                }catch(InterruptedException e){
                }
            }});
    test2. start();
}
public static void main (String[] args) throws Exception {
    BufferedReader br= new BufferedReader( new InputStreamReader(System. in));
    br.readLine();
    createBusyThread();
    br.readLine();
    Object obj= new Object();
    createLockThread(obj);
}

監(jiān)控線程的Runnable 狀態(tài)

我們?cè)诰€程 tab 中可以看到 main 線程,你可以看一下圖片。右側(cè)堆棧顯示 readBytes 在參數(shù)輸入,此時(shí)線程還是 Runnable 狀態(tài),Runnable 意味著線程會(huì)被分配 CPU 時(shí)間片,readBytes 發(fā)現(xiàn)沒有任何輸入又會(huì)歸還 CPU 時(shí)間片,這種性能消耗幾乎可以忽略不計(jì)。

圖片圖片

接著監(jiān)控 test1 線程,test1 線程執(zhí)行的是自旋操作,從右側(cè)的堆棧中我們可以發(fā)現(xiàn)線程此時(shí)在 MonitoringTest.java 代碼的 41 行,而第 41 行就是死循環(huán)。顯然這種自旋會(huì)極大浪費(fèi) CPU 資源。

圖片圖片

監(jiān)控線程的 WAITING 狀態(tài)

下面我們?cè)賮砜纯?test2 線程,圖片顯示 test2 線程在等待某個(gè)鎖,線程這時(shí)候處于 WAITING 狀態(tài)。test2 線程處于一個(gè)正常的狀態(tài),它在等待一個(gè)鎖,直到鎖對(duì)象被 notify 調(diào)用才會(huì)繼續(xù)執(zhí)行。

圖片圖片

監(jiān)控線程的 BLOCKED 狀態(tài)(死鎖)

下面我們看一個(gè)死鎖的例子。出現(xiàn)線程死鎖之后,我們可以看到一個(gè)新的“死鎖”tab。

圖片圖片

圖中我們可以很清晰地看到 43 號(hào)線程在等待一個(gè) Integer 對(duì)象,這個(gè)對(duì)象被 12 號(hào)線程持有。而點(diǎn)擊 12 號(hào)線程則顯示它也在等待一個(gè) Integer 對(duì)象,這個(gè)對(duì)象被 43 號(hào)線程持有,43 號(hào)線程和 12 號(hào)線程形成了死鎖,是不是很直觀?

總結(jié)

以上就是我們講的 JConsole 的常用用法,可以看到,我們?nèi)粘5谋O(jiān)控、死鎖判斷、內(nèi)存排查都可以使用 JConsole 去排查。在沒有圖形化的生產(chǎn)環(huán)境可以使用 JConsole 遠(yuǎn)程連接。對(duì) JConsole 的使用大多數(shù)是線上問題診斷。既然要診斷,最重要的還是基于我們的研發(fā)經(jīng)驗(yàn),JConsole 只是工具而已,不能本末倒置,認(rèn)為有一個(gè)工具就可以解決問題了,更需要的是我們?nèi)藶榈呐袛唷?/span>

此外,我們通過線程 tab 看到了線程的 Runnable、WAITING 以及 BLOCKED 3 種狀態(tài)。要特別注意區(qū)分 WAITING 和 BLOCKED 狀態(tài),簡(jiǎn)單來說 WAITING 和我們的 wait 方法有關(guān),而 BLOCKED 則和鎖有關(guān)。

責(zé)任編輯:武曉燕 來源: 程序員技術(shù)充電站
相關(guān)推薦

2021-07-14 09:00:00

JavaFX開發(fā)應(yīng)用

2022-12-07 08:42:35

2021-08-02 07:35:19

Nacos配置中心namespace

2011-01-10 14:41:26

2011-05-03 15:59:00

黑盒打印機(jī)

2021-01-19 09:06:21

MysqlDjango數(shù)據(jù)庫(kù)

2020-05-15 08:07:33

JWT登錄單點(diǎn)

2021-03-12 10:01:24

JavaScript 前端表單驗(yàn)證

2022-07-22 12:45:39

GNU

2021-12-15 08:49:21

gpio 子系統(tǒng)pinctrl 子系統(tǒng)API

2022-10-30 10:31:42

i2ccpuftrace

2022-01-08 20:04:20

攔截系統(tǒng)調(diào)用

2023-04-26 12:46:43

DockerSpringKubernetes

2022-03-14 14:47:21

HarmonyOS操作系統(tǒng)鴻蒙

2022-07-27 08:16:22

搜索引擎Lucene

2011-02-22 13:46:27

微軟SQL.NET

2021-02-26 11:54:38

MyBatis 插件接口

2021-12-28 08:38:26

Linux 中斷喚醒系統(tǒng)Linux 系統(tǒng)

2020-08-12 09:07:53

Python開發(fā)爬蟲

2020-12-08 10:32:15

Python郵件tcp
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)