00:00
那接着咱们来看这个第四节,叫做MAT和j profile的一个jc root溯源,那什么意思啊,就是咱们呢,在前边呢,是不是提到在Java当中咱们使用的叫可达性分析算法,对吧?诶来进行这个垃圾的一个标记,那么可达性分析算法的话呢,我们说还有一个名字呢,叫做根搜索算法,那这个跟搜索算法的一个来源呢?诶就是因为呢,咱们需要在这个程序当中确定呢,是不是哪些引用可以作为这个叫j c root呀。对吧,哎,确定了这个J些root以后呢,我们看跟它关联的,通过这个引用链关联的这些对象呢,他们就是可达的对象,就不应该被回收,而没有被关联的这些呢,是不是就应该是垃圾应该被回收,对吧。哎,这呢,就我们说的叫,诶跟搜索算法。那当然了,我们说这个567这三个对象呢,也不一定说一定会被回收,为什么呀,因为呢,我们是不是还提到一个对象呢,叫finalization这样一个机制,哎,他们在回收之前呢,调用这个finalize方法的时候啊,有可能又被复活掉了。
01:01
啊,又复活了,诶有这样一个行为啊,咱们上一节呢,已经讲过这个问题了,行,那么这一节咱们想说的问题呢,就是说这个jc root到底,诶我们在一个程序当中啊,比如我们把一个程序呢给它跑起来,跑起来以后呢,这里边到底有多少个jc root呢,分别又是什么呢?这块呢,我们可以通过一些工具呢,来进行一些查看,那这个工具呢,就是咱们现在要讲的啊叫MAT呢和jepo这个jepo file的话呢,咱们前面讲内存结构的时候呢,是不是带着大家使用过这个jpo对吧?咱们当时用的比较多呢,是jpo和这个JVVM,诶这样的这个两个工具。哎,这两个工具,那为什么现在说不用这个JVVM呢?呃,因为呢,在这个呃显示jc root这个方面的话呢,这个JVVM的话,相对来说没有我们这个MAT呢更方便一些啊应该这样来讲。啊行,那MAT的话呢,这是咱们第一次来讲,那首先来看一下什么叫MATMAT的话呢,叫memory and lazer啊,T啊,To啊,就是内存分析工具的一个简称,是一款功能强大的Java堆内存的分析器,那用于查找内存泄露以及查看内存消耗的一个情况。
02:11
那其实的话呢,跟咱们说的这个叫比如说JVSOV啊,J proler呀,包括j conso啊等等,他们其实都是类似的,哎,查看我们这个内存的一个消耗情况,内存泄露啊,哎包括呢,我们是不是有一些死锁呀等等的问题啊,说白了就都是咱们用于叫这个性能监控和调的一些可视化的工具,后边呢,咱们讲到这个下篇的时候啊,咱们这是不是还有个下篇是吧?诶重点呢,给大家讲一些这个命令行的,还有呢,咱们这些具体的可视化的一些工具。啊,这里边对大家要求呢,就是你至少得有一款工具呢,应该叫熟练使用,比如说呢,关于这个j profile啊,你可以呢熟练使用,那剩下的关于这个叫JVVM呢,接councilo啊,这个MAT啊等等啊这些呢,你可以去熟悉。啊,因为呢,具体的这些工具呢,他们呃,毕竟是不同公司开发的,他在某一些方面呢,可能呃,这个工工具呢,一般啊那个工具呢,可能更强大一些,大家呢,可以借助一些不同的工具呢,进行一个查看是吧?啊当然你有一款呢,相对来说啊,要能够熟练使用啊。
03:12
行,那么关于这个mitt的话呢,它是eclipse开发的,是一款免费的性能分析的工具,那当然呢,可以通过这个官方的链接地址呢进行下载啊,这个链接地址你也能看到,就是eclipse啊,这呢我提前打开了,因为我这个网呢,这个稍微差一些啊,我就提前给大家打开了,那就是这个网址,这呢就是我们这个工具,然后呢,大家可以呢,去下载一下这个版本。那这呢是这个3月18号的啊,有段时间了啊,那这样下载或者呢,我给大家发的这个课件里边呢,咱也有。啊,打开他们这个上片这个软件。在这是吧,哎,我这是1.9的版本,这个呢,相对来说这个新一点是吧,哎,当然我们现在的使用的话呢,用哪些都可以哈,咱也不是用这个新特性里边的一些东西的,行这呢就是我们说的这样一个工具啊,诶这是它这个界面。
04:01
行,那咱们使用这个工具的话呢,就可以去分析咱们当前的某一个程序当中到底有哪些叫g c root。啊,但现在的话呢,我们不是说直接在这块来看,咱们可以使用一种叫离线的方式。啊,一种离线的方式,然后呢,这里边儿就涉及到他们之间交互的一个媒介呢,称为呢,叫做dump文件。啊,就生成咱们对空间中的这个程序运行的一些文件啊,数据生成的文件,那如何去生成这个大文件呢?啊有两种方式,我这呢给大家列的啊第一种呢叫JA map。这个解map呢,我还不想在这块给大家去讲,我下边到时列了一个例子哈,诶我就不想讲了,因为呢,咱们讲到这个下篇性能监控与调约的时候呢,咱们要去讲这些具体的命令行的一些指令啊,使用这个j map呢,咱们就可以去生成这个叫离线的这种大文件哈。呃,首先呢,是使用这个GPS去查看一下咱们当前这个程序当中,这个进程有哪些啊,比如说呢,我们把这个程序呢,运行起来啊,这是它的这个进程ID啊,然后呢,通过我们这样的一个指令。
05:01
哎,你呢去生成这个bin文件,这呢就是我们所谓的叫大MP文件啊,我这呢是生成了两个。其实生成一个就可以是吧,生成两个呢,我们是想额外的说明一些其他的问题,那一会儿呢,咱们也会生成两个啊行,这是使用这个命令行的方式,大家如果想测试,你就自己来按照我这个写法,你自己来测试一下就行,我这就不演示它了啊,时间关系,然后的话呢,第二种方式呢,叫使用接收JVSOVM,就通过我们这个可视化的这个界面啊,点一点就能生成这呢,我们主要给大家演示的啊,是这样一种方式。好,那首先的话呢,咱们来看一下咱这个程序啊,这个程序呢,我是这样写的。这呢是一个没方法。在这个main方法里边呢,我生明两个是不是局部变量啊啊,两个局部变量行,那么大家也知道这个may方法,咱们对应的这个线程呢,可以称为叫主线程啊,在这个线程当中,咱们有一个may的一个战帧。啊,那这个战争里边有局部变量表,局部变量表里边存放的就是我们这个方法中的这个局部变量,比如说这个X,比如说这个number list啊,比如说我们这个birth。
06:02
啊,都是是吧,那局部变量表咱们前面讲过,它们是不是就是天然的作为这个g c root呀。哎,当然我们说这都是引用是吧,你指向你对空间,你用的这个对象,他们就是这些root啊,咱们一会看导出的这个大部分文件里边能不能看到他们俩。啊,能不能看到他们俩行,嗯,这是我们说的这个程序,把这个程序跑起来以后呢,我们通过循环的方式往里边去添加一些数据到这个release当中啊填的稍微慢一点,然后这块呢,我们有个阻塞,呃,在这个程序执行到这的时候呢,我们导出一个单MP文件,然后接下来呢,我们,诶输入一个数据呢,它就又停到这了,咱们再导入一个单文件,那么这两个区别是什么呢?就是我把这两个引用的哎,指针是不是给它干掉了。哎,只成了是no了,那导致呢,就是我们这个大文件跟这个大文件的区别呢,就在于我们这两个堆空间中的实体。那是不是就没有意义了?对吧,哎,就可以作为这个垃圾呢,要被回收了啊,就是这样的区别,行把这个成语呢,咱们跑起来。
07:05
OK,画下来以后的话呢,这个时候我通过这个叫JVSOVM呢,咱们去把它,诶大文件呢,导一下啊生成一下。首先呢,选中咱们当前的这个进程。然后呢,诶,咱们在这儿有个叫监视,监视这块呢,有一个叫堆dump。那叫对,咱们点一下。好,你看此时呢,及时性呢,就帮我们生成了一个快照啊,这个08:58是吧,这样一个快照,这个快照的话呢,你注意啊,嗯,我们如果要是关掉。当年这个JVM的话呢,它其实就没有了。啊,它就没有了,诶所以呢,它是个临时的,如果大家想把这个文件呢,给它保存下来的话呢,你就点一个右件这个一个叫另存为是吧,比如在桌面上我们去生成一个文件夹啊,比如我们就叫做这个叫dump。哎,我这块呢,打开一下。啊,保存行,我就放进去了,这是一个行,然后呢,你把这个给它关掉,关掉以后呢,再看到我们这个监视,监视这个时候呢,我们再去点一下,这个叫对于大盘看点。
08:07
那这是我一点,你看大家会发现呢,此时是不是又生成了一个快照啊。这就是两个不同的这个文件啊,能理解是吧?啊行,这个呢,我们生成它好像没啥用,因为我这俩没什么区别,那咱在这块呢,这样刚才呢,生成的这两个快照呢,程序都是停在这儿了啊都停在这儿了,下边呢,我们写一个叫继续执行是吧。一回车,那此时的话呢,我们就把这两个变量呢,你看都制空了,相当于此时呢就阻塞到这儿了。啊,组组到这了,然后在这个时候呢,咱们去生成一个快照啊,就刚才这俩其实没什么区别,咱们再去点这个监视,我再点一下这个对啊点。啊,这时候我一点,你看生成的是不是这个文件啊,哎,这个文件里边呢,就把刚才说的那两个变量就滞空了,我点一下右键叫另存为,哎,反放到这个桌面上啊。啊,这是494,这个是989。诶,保存一下。
09:00
那么这个程序呢,对咱们来说呢,也没什么用了,我这块呢,就点一个输,输入一个叫结束。它成语呢,就结束了,好收起来,那这个呢,呃接VCVM呢,对于我们说呢,也就没啥用了,哎这呢,我们里边是不是就生成了这两个文件了。可以是吧,行,那接下来的话呢,我们就使用这叫MAT这样一个工具打开。行打开以后的话呢,这个welcome呢就不用欢迎了,在这个file这块呢,有一个叫open file找到我们桌面。那咱们的桌面。呃,这个叫dump,咱们先是生成的这个1494是吧,先给它打开一下。诶可以了,哎可以了,行,那针对于咱们当前这个程序的话呢,我们,诶在这块点一下这个叫Java basic,然后在这块你看我们就能看到叫jc root。可以了,诶打开以后大家会发现哦,我们当年这个GC root啊还挺多的啊,1700个。能看到这个数是吧?啊1700个行,那么都有哪些可以作为这个jc root呢?你看这里边列出来,这叫system class啊,我们说叫系统类啊,这一打开啊还是挺多的。
10:08
铁头这里边细节我们也打开了,你看1654个对吧,诶这呢就涉及到我们这个,呃,有一些这个系统类加载器啊,或者还有我们这个引导类加载器,加载的一些具体的这些类。啊,这体一类行,这是它,然后下边这个呢,叫GI global啊涉及到我们这个本地啊方法当中加载一些相关这个类的一些结构。啊,这是这个,然后呢,还有这个叫thread啊thad,就我们当前这个线程当中是吧,然后下边还有这个busy monitor啊,这也涉及到我们这个锁对象啊锁对象是吧?锁对象呢,我们不是说也是要作为这个诶J些root吗?行能看着了是吧,哎,这我们说这个,然后大家会发现说这个这个列的这个结构啊,怎么感觉跟咱们前面讲的这个g c root。嗯,说的这个,嗯,好像有点区别是吧,咱们是不是说的时候是按照内存结构来说的,而这个呢,是不是另外的一个维度啊,诶另外的一个维度,那这呢,主要原因是因为咱们这个啊eclipse这个事啊,我在这个。
11:08
PPT当中啊,有这个说明。嗯,我在这啊,这呢有个链接,大家把这个链接的话呢,你拷贝一下放到我们这个浏览器当中啊,这呢我已经提前打开了啊,就是刚才说的这个链接,这呢是eclipse这个官网当中对于这个叫garbage collection roots的一个描述。啊,你看这个描述当中,System class啊,Local global thread busy monitor,你看这个描述是不是说跟我们现在看到这个结构是一样的,对吧。啊,这就是不同的这个维度啊来说明的啊,这个大家不用紧张啊,哎,不管呢,是用什么样的方式的话,我们整个这个GC root呢,诶都是一样的,只不过分法稍微有点区别而已啊。行,那我们这块来看一下,在咱们这个线程当中,这有个叫long的一个thread,再打开,打开以后呢,往后拽一下。诶,这呢,是不是涉及到一个叫主线程啊。
12:02
啊,Main线程对吧,哎,这是这个主线程,然后呢,你看这块还有这个叫哎finalizer,就我们说垃圾回收的这个线程是吧?哎,用于去调用咱们这个finalize方法的啊,优先级比较低,行,然后这个main线程呢,咱们再打开。那这呢,一共就看到这些结构是吧,这些结构里边呢,咱们找一下你会发现呢,是不是里边有这叫a list,哎,是不是有我们这个date呀,还有咱们这个may方法的一个行参,还没方法行参就是我们这个结构。这是吧,诶他们呢,你看是不是都是作为咱们这个叫诶g c root出现了。没问题是吧,诶这呢,就是我们能看到这个诶g c root行,然后呢,咱们再去诶open一个file。嗯,这块呢,咱们把那个是不是还有这个叫989是吧,把它那打开一下。行,然后同样的。嗯,找到这个JC。哎,在这块,然后找我们这个thread,哎,找我们这个thread。
13:01
找我们这个主线程是吧?行,这时候呢,大家你再去找,是不是有我们这个date类型的对象,还有我们这个叫list类型,你发现就找不到了,你看此时呢,在这块例举出来的当前,它下边呢,你看是不是有19个。是吧,19个,而我们刚才这个位置呢,你看这是不是有21个呀,诶差的这两个呢,就是咱们刚才看到的这两个没有了。哎,他俩没有了,嗯,OK能理解是吧?行,那通过这个MAT这个工具呢,咱们就能查看一下哦,到底哪些诶是作为咱们这个jc root出现的这些引用,OK,这呢就是给大家演示一下叫it的一个使用啊。
我来说两句