粉丝3.7万获赞14.1万

下面看下我们的 g c, g c 是我们垃圾回收的缩写,它指的是我们一种垃圾回收机制,专门用来回收不可用的变量值所占用的一个内存空间。那么 java 堆是我们 g c 垃圾回收的一个主要区域。那么下面我们看一下为什么要使用 g c。 在我们程序运行过程中,我们需要申请大量的内存空间来存储我们的数据,然而如果这些内存空间如果没有被及时释放的话,他就会导致我们内存使用殆尽,即所谓的内存溢出,那么内存溢出会导致我们程序崩溃。因此在我们程序中管理内存是一个非常重要且复杂的任务。 好,那么下面看一下我们垃圾回收的方式,比如说我们的样 gc, 也可以叫我们的 menagc。 我们年轻态空间是垃圾回收的一个主要区域,因为通常在程序运行初期,大部分对象都拥有短暂的生命周期,并且很快变得不可达, 所以我们年轻代空间中的对象很快可以被清除。那再一看我们的 word g c, 我们也可以叫麦角 g c, 它主要是针对我们在年轻代空间中存活的对象。 那么在程序运行过程中,我们一些对象可能在年轻代空间中存活下来,并被移动到我们的老年代空间中。因为我们老年代空间中的对象比我们年轻代空间中的对象说明更长,那么他垃圾回收成本更高,因此我们老年代机身的执行频率较低,但是他需要时间更长。 好,再看我们的 fourtc, 我们 fourtc 是一个全量垃圾回收,它是一个扫描整个家瓦堆内存的过程,包括年轻袋和老年袋空间。在 fourtc 中,我们垃圾回收器会查找所有不再需要对象并释放他们占用的内存。通常情况下,当没有足够的空间分配新对象或者我们 d v m 检测到对内存已经满时,那么我们的 forgc 就会被调用。与我们的样 gc 和我们的 od gc 相比,我们 forgc 通常是一个更昂贵的操作, 因为它必须扫描整个加瓦堆内存并处理大量的对象。然而, four g c 可以有效的释放大量的内存并减少城市的内存占用,因此它仍然是必要的。

来看这道面的题,有没有处理过线上内存溢出 om 的问题,你是如何定位排查的?我们来说一下 om 是什么呢?内存溢出对吧?就是我们的应用频繁的发生复偶, gc 老年代爆满,无法进行回收,那就会造成内存溢出的这个异常。那面试官呢,有可能会这么来问你,当我们的服务器上面部署了,就要应用出现了 out of memory exception 的异常,那有可能是什么原因造成的呢? 又如何来进行定位呢?所以说这里是两个问题,那我们应该如何回答呢?当然,嗯,不同的项目情况回答起来肯定也是不一样,还得结合你自己的一些经验啊,以及啊, 不同的情况,我们可能使用不同的命令,使用不同的工具,都可以来定位 om。 那徐老师希望通过本视频呢,给大家提供一个普遍的这样的 om 解决的思路,以及面试的回答。好吧, 那我们首先要搞清楚 om 造成的原因会是什么呢?在这里我给大家总结了三点。第一点,有可能呢,是你的应用一次性申请的对象太多了, 就比方说有的同学去做一些数据列表的查询,他有可能呢,会一次性的去数据库把所有的数据都搂过来,那你想一下,如果你的数据量达到了千万级,你把所有的数据都放到历史当中, 那有可能就会造成内存溢出,对吧?那我们要解决这个问题呢,只需要去根 更改申请对象的数量,就比如说我做个分页,我一次性呢啊,查个十个一百个都是可以的,对吧?那另外一种情况呢,就是内存资源耗尽没有释放, 那我们经常比如说会去使用现成啊,对吧?或者说使用数据库查询啊,那么在高并发的情况下,假如说我们不断的去创建现成, 不断地去使用这个 gdbc connection, 但是呢又没有去释放,那久而久之呢肯定就会造成内存溢出,对不对? 所以说这种情况我们要解决呢,我们可以及时的去释放,比如说我们的 connection 用完之后立马去关闭,当然我们可以引用磁化的思想,对不对? 也就是我最多呢只申请,比如说一百个资源,或者说十个资源用到了这个我就阻塞不再申请了,那这种方式呢,我们就可以解决这种内存资源耗尽未释放的问题。 那第三种就是你本身应用给他分配的这个堆内存的资源就不够,无法支撑我的应用日常的一个呃操作, 就比如说我的这个应用当中,他本身就有一些比较大的对象,那要支撑我日常的一些基本的业务操作,你的堆内存如果不够的话,肯定就需要调整你的堆内存,对吧? 那针对第三个问题,我先给大家演示一下,好吧?来,就比如说我这里呢有一个简单的计划程序, 我们先把它跑起来,那里面的代码是什么,我们先不要关心,好吧?我们可以呢先查看一下当前这个应用 它的一个这个堆分配的是多少。就比如说我们运行了一个二四零八八的一个进程的抓应用,那我们可以通过机 map 干 hip, 然后加上这个进程二零八八,那么此时呢,他就会为我们打印当前这个 dr 应用,他所使用堆的一个最大的内存,以及呢你的这个新声带他使用了多少内存?空闲多少? 然后呢你的一零元区对吧?你的 slow 一 slow 二区,以及呢你的老年代,你的内存多大,使用了多少?空行多少?那么根据这些指标呢?呃,在结 和你的应用,你可以适当的去做一些调整,当然这里你得对 g m 的一些概念肯定要有所了解,对不对?嗯,这个是这个问题啊,如果你本身 对内存分配不够的话,你可以通过这个命令来进行查看,那然后呢进行相应的调整。那针对第一个问题跟第二个问题,我们应该怎么解决呢?那我们肯定得定位到对应的这个业务代码, 对不对?比如说一次性申请的对象带刀,我肯定要找到对应的验货代码,然后改一下他申请对象的数量,那么这个也是,如果我们的某一个资源没有释放,我肯定得找到对应的代码,然后呢给他及时的释放掉。所以说这个问 题我们得去定位,也就是怎么快速的去定位线上的 om。 那我们要定位 om 的话,我们也分不同的情况,第一种就是如果你的系统挂掉了的话,又应该怎么定位? 第二种就是如果你的系统正在运行,还没有 om, 又应该怎么定位? ok, 我们先来说一下第一种啊,也就是如果你的系统挂掉了,又应该如何定位呢?我们通常呢会通过一个叫做堆的档谱文件, 这样我们才可以有效的快速定位。好吧,那如果你的系统已经挂掉了,并且呢,你没有在运行你的程序的时候呢,去设置这个 gm 参数的话,那他就不会怎么样呢?这个参数什么意思大家 知道吗?他会在你的呃应用 alt of memory 的时候呢,为你导出一个堆的弹谱文件,导出到你指定的目录当中,那通过这个弹谱文件我们就可以来分析 o m 溢溢出的一个具体的代码位置, 所以说如果你没有设置这个参数的话,那你可以呢提桶跑路了,因为你无据可查,知道吧?那接下来我就给大家演示一下,当我刚刚给大家跑的这个应用,如果他内存溢出了的话, 我们应该如何的进行快速的定位,好吧,当然他现在呢还没有挂掉啊,好,大家可以看到我刚刚暂停了一下,那现在呢就 auto of memory r 内存溢出了,对吧?那如果我们内存溢出了,你没有去给他设置这 一个参数的话,那你可能呢就无据可查了。当然你有可能能够根据这个呃县城站中的信息能够追溯到异常的位置, 但是我们真正线上的这个系统呢,往往要复杂的多,对吧?因为我们会有很多的线程,所以根据这个异常是很难定位到的, 所以说,呃建议大家呢,可以将你的系统呢无脑的去设置这个参数,好吧,当然是一点啊,你一定要保证你的这个呃系统的硬盘空间够大, 因为他会记录你的系统在整个运行的过程当中所有的一些对象的信息,所以说呢,呃也是非常占我们磁盘空间的,也就是他 导出的时候呢,有可能这个文件会很大好吧,但是呢能够在你出现了 om 能够快速的定位,所以我们来给大家演示一下,好吧,那接下来呢,我们就运行我们刚刚的那个召唤程序,我先我先听一下,行吧, 这,然后呢加上我们的 g m 的参数, 那在这里呢,为了能够更快的 om, 我将我的堆的内存呢设置为了十兆,那么这样就能够很快看到我们的 om 的异常了,好吧, 然后呢加上我们刚刚所说的这两个关键的参数,也就是在内存溢出的时候呢,会帮我们导出堆的弹谱文件到指定 的目录当中,那在这里呢,我们就指定到当前 home 这个文件夹的这个 g v m logs, 好吧,我们就用相对路径, 然后落个四啊,当然你也可以指定这个文件文件的名称,如果你不指定的话,他会根据你当前这个应用的进程生成一个文件,好吧,我们就不给他指定,然后呢干架去运行我们的 g m ganzam 回车, ok, 他马上呢就会内存溢出了,大家可以看到,那并且呢他帮我们在这个目录下生成了一个当前这个进程的一个当补文件,我们可以来到这个 g m logs 啊,这里呢由我之前生成的一个,那这个就是我们刚刚 生成的这个,那接下来呢,我们就利用这个叉 f t p 将这个文件呢给它导出到我们 windows 的磁盘当中,我们再确定一下,是这个二四二三二,对吧?这个文件我们把它导过来, 我刷新一下啊, ok, 有了,对吧?那接下来呢,我们就去结合叫做 we still vm 的一个工具去载入这个 dump 文件来进行定位 om, 那点击这个文件,然后点击装入,将刚刚的这个档谱文件二四二三二给它载入进来,这里注意啊,你要选择 堆好吧,否则的话你选不到, ok, 那首先我们可以看到他在这里呢,给我们显示了当前这个档谱文件他的字节数啊,里面类的总数啊,然后实力总数是多少啊?那 我们最主要呢,可以先点击这个类选项里面。 ok, 这里大家可以看到在我们这个应用运行的过程当中所 用到的这些实力,它的一些实力数,然后占到的大小,那我们肯定找到最占内存的一个实力,对不对啊?当然你像这些 char 啊, string 啊, intake, 我们可能 无法明确的定位到,对吧,但是一看这个,哎,这个好像就是我应用程序当中用到的 后就点 us 对不对?那我们可以找到我们在业务当中用到的一些对象,然后呢双击进来啊,那么这里呢,他就给你列出来了所有的 实力数,好吧,当然我们一般情况下呢,只需要点击某一个,然后呢你展开找到这个 g c root 啊,那么 g c root 呢,就是这个三角形表示的就是垃圾回收的根节点,也就是我们的 g c root, 那么通过 g c root 呢,我们就可以 显示当前这个 g c root 它的现成的引用,然后点击进来,我们可以看到当前这个 user 它在我们的 every list 当中使用了,并且呢使用的地方是在这个 user service 点 get use 方法,并且是在十七行。 ok, 那我们就可以来到我们的应用程序啊,我们找到我们的 user service 十七行,是不是就是在这里啊?在这里呢,我们写了一个死循环, 无限的去添加 u 四对象,最终造成了我们的啊 om, 所以说通过这个档谱文件,然后结合这个 gvsovm, 我们是不是就能很快的定位到这个 om 的问题啊,对不对? ok, 那这是一种情况啊,也就是我们的系统已经挂掉了,建议大家呢,在运行的时候呢,加上这个 gm 参数,那么你就可以通过档谱文件来快速的定位, ok, 那第二种情况呢,就是我们的系统还没有挂掉, 那你要去分析要怎么办呢啊?当然你可以呢在他运行的阶段去导出一个弹谱文件,好吧,或者说呢,呃,利用阿尔萨斯这种调试工具 来进行调试,那么阿尔萨斯这个工具呢?我在这里,呃,先不讲了,好吧,同学们如果有兴趣呢,呃,可以给老师点一波赞,如果赞达到了一千个呢?徐老师后续给大家更新一个怎么通过阿尔萨斯来进行一系列的故障的一些个呃,调试,好吧, 那我们在就是系统还没有挂掉的时候,我们可以导出一个档谱文件,当然有的同学会说啊,老师你在系统运行的阶段去导出档谱文件,会造成我们的一次 g c, 然后呢会造成 stop the word, 也就是所有的线程呢都会中断,但是你要知道,如果你不导出这个当谱文件的话,你要付出成倍的时间来去定位,就比方说来再给大家演示一下, ok, 来,我们继续去运行刚刚的那个应用程序叫干架,那么接下来呢,我们就先不让他挂掉了,好吧。 啊,我们要回到上一层,然后呢去运行这个 job, 干加 g m 干 demo, okay 啊,稍等一下啊,我忘记让他在后台运行了。 ok 啊,那接下来如果说我们不导出这个档谱文件,那你只能 怎么样呢?你只能通过,比如说通过这个命令禁麦法干黑 history, 然后呢, life 输入你当前这个进程的 it, 他让我,我找一下,我刚刚清了屏,对吧?我们可以通过 gps 来找到当前的这个抓进程,那这个就是我刚刚运行的这个抓进程,那我们通过 gmap 干 histo, 然后呢?呃, life, 也就是你当前存活的对象,输入你的进程 id, 二四二八六,回车。 稍等一下啊,比较多,那我们可以看到啊,他就会把你最占内存的这些呃对象给你显示出来,其实就 就是我们刚刚利用这个 g visa vm 的这个面板,其实这里通过这个工具操作出来的这种可视化的界面呢,其实他也是使用的这些命令,知道吧?那你用这个命令的话,你要定位,你只能 说我看到好像当前这个 user 比较多,对不对?那你就没有办法像我们刚刚那样啊,能够快速的去定位他的这个 gc router, 然后他的这个线程引用了, 所以呢,你要付出更加成倍的时间去定位这个问题, ok? 或者说呢,你使用像这种阿尔萨斯的这种故障的啊调试工具, ok, 好吧,所以说 为了更加快速的去定位 om 呢,我们还是建议大家呢,去使用这个命令。 ok, 来,我们打上这个击 map 干 dump, 然后 format, 我直接复制一下这个说实话我也记不住这些东西,谁会去记呢?对不对? ok, 然后这里呢,我们改一下,改成我们当前的这个进程 id 是多少啊?刚刚打印二四二八六,对吧?二四二八六,回车, 那么他打印到的是在我当前,好吧,我们依然把它打印到 gvm logs 里面的徐数, 然后点这个后缀回车,我们来看一下, 已经导出了啊,然后呢,我们一样的,我就不继续给大家去做调试了,好吧,一样的,利用我刚刚的这种思路,利用这个叉 f t b 呢,把它拿到我们的 windows 环境,然后结合这个微收 wem 去进行定位就可以了。 ok, 那这是第二种,我们可以通过这个命令呢来在线的去导出 double 文件,虽然它会造成我们这个 g c 的 stop word, 但是呢,为了更加快速定位 o m, 我觉得是值得的。 ok, 当然我不可能说我一上来就直接对我正在运行的这个应用直接就导出当补文件,对吧?我们得有理有据,就比如说我接收到了平房负 g c 或者说 c p u 漏的标高的一些告警,那么这个时候我才来 到我的服务器呢,去导出这个档口文件,然后呢进行调试啊,那么这就是我们如何快速定位 om 的一个思路啊,大家可以也就是说在你抓二程序运行的时候呢,去设置这个命令,好吧,去导出档口文件, 然后如果你的系统还没有挂呢,你可以就是运行的过程当中呢,直接来进行导出,然后呢去结合我们的 g vsovm 来进行调优,找到跟你业务有关的一些对象, 然后呢找到它相应的这个 gc rot, 然后点击右键查看县城站,那么就可以呢来快速的定位对应的这个业务代码了。 ok, 好,那么这个问题呢就给大家讲到这里,那我在这里呢也是给大家准备了一份这个快速定位 om 的我课上的一个思路的文档,那么同学们需要的话可以来加我领取,好吧?

勾烂垃圾回收第三色标记法,灰色对象还在标记队列中等待,黑色对象已被标记, good chronicless 对应的为唯一,该对象不会在本次 gc 中被清理。白色对象未被标记。 good clark beats 对应的微微零,该对象将会在本次 gc 中被清理。当前内存中雷 f 一共六个对象跟对象类 b 本是认为占上分配的局部变量, 跟对象啊 b 分别引用了对象啊 b, 而逼对象又引用了对象 d, 则 gc 开始前各对象的状态如下图,琐事初始状态下,所有对象都是白色的,接着开始扫描跟对象呢 b 由于跟对象引用了对象 b, 那么啊 b 变为灰色对象,接下来就开始分析灰色对象。分析 a 十 a 没有引用其他对象,很快就转入黑色 b 引用了 d, 则 b 转入黑色的同时,还需要将 d 转为灰色进行接下来的分析。上图中灰色对象只有 d, 由于 d 没有引用其他对象, 所以低转入黑色。标记过程结束,最终黑色的对象会被保留下来,白色对象会被回收掉。