La memoria del servidor fue reventada por un hilo de Java ese día, un simple proceso de diagnóstico de problemas JVM

Soy una cometa, el número público "Kite in the Ancient Times", un número público técnico que no solo es técnico, un desarrollador de barras que ha estado involucrado en el círculo de programación durante muchos años y se dedica principalmente a Java, y también a Python y React. La serie de artículos Spring Cloud se ha completado, puede ir a mi github para ver el contenido completo de la serie. También puede responder a "pdf" en la cuenta pública para obtener mi elaborada versión en pdf del tutorial completo.

Hablando de comer al mediodía ese día, un colega dijo: "La persona del equipo del proyecto está enojada conmigo, hay un problema con el programa. Por la mañana, estaban en el grupo @ ellos, y no respondieron el mensaje hasta el mediodía, e incluso dijeron que su programa no era un problema". , Se llama con demasiada frecuencia de nuestra parte. Solo quiero reír ".

En términos generales, si hay un problema con el acoplamiento, si el error no es demasiado obvio, dudaré primero si hay un problema yo mismo, para no ser vergonzoso. Así que dije, regrese después de comer y lo ayudaré a verificar dónde está el problema.

Nota de antecedentes

Nuestro sistema actual está integrado con muchos sistemas de terceros, y el problema es uno de los sistemas de tres partes. De hecho, es muy simple, su sistema generará algunas tareas de tareas personales, y luego el número de tareas de tareas debe enviarse a nuestra APLICACIÓN, que se muestra como la esquina del icono.

Los datos del usuario se han borrado. De hecho, es un requisito muy simple y no se requiere que la notificación de la esquina sea en tiempo real. Se puede pasar una vez cada 10 minutos. Este escenario es muy típico, y el uso de colas de mensajes es perfecto. Empujaron los datos a la cola de mensajes, y fuimos a la cola de mensajes para obtenerlos, perfecto.

Sin embargo, este no es el caso. Dicen que el sistema está productivo y no admite colas de mensajes. Solo puede abrir la interfaz de tareas pendientes. Bien (cara sonriente), tú eres el producto y eres razonable. Es posible que no haya muchos usuarios con tareas pendientes, más de 300, luego solicite más de 300 solicitudes cada 10 minutos. No hay necesidad de subprocesos múltiples, es decir, simplemente hacer un bucle de más de 300 solicitudes, cada vez toma aproximadamente 1 minuto.

Está bien, así que canta.

Por cierto, el JDK de este servicio es la versión 1.6 Se dice que, por razones históricas, ya no se atreve a actualizar. Además, el servicio debe implementarse en Windows. (Dices que la magia no es magia)

Floreciente

Luego cante así, sea una tarea programada y pida 300 veces en 10 minutos, lo cual es bastante agradable y sin preocupaciones.

但是好景不长,天不遂人愿,服务器不遂程序员愿。

以下是同事的经历,我转述以下。

就在定时任务跑起来后的第二个晚上,那本来该是一个平常的晚上,可是告警邮件扰人清梦。一看日志,内存使用空间过高,撑爆了,导致机器自动重启了。windows 就这点好啊,还会自动重启(尴尬脸)。然后手动上去把服务启动起来,解决。

隔了一天,还是晚上,又报警了,服务器又自动重启了,又是内存使用空间过高。又手动上去把服务启动了。

于是他反馈给这个服务的开发人员,结果得到的回复是:“我们的服务没有问题,肯定是你们的调用有问题,你们把定时任务停掉肯定就好了,所以是你们的问题”。

于是,他过来找我,跟我说明情况,问我可能会是什么问题。

我:你确定定时服务是 10 分钟一次,没有出现死循环吗?

同事:确定。

我:那他们的服务有使用 redis 之类的外部缓存吗?

同事:不知道。

我:。。。 既然你确定你调用的没问题,那肯定是他们程序出现问题把内存撑爆了呀,这有什么好怀疑的,让他们改吧。

同事:他们现在说自己没问题啊。

挖出真凶

好吧,既然他们说没问题,那我就来帮他把问题找出来吧。于是,远程进了那台 windows 服务器。

这时候已经把定时任务已经跑了两天了,16G 的内存已经用掉 15G 多了,眼看随时有可能崩溃,然后把定时任务停掉,内存使用量也并不会下来。

我开始怀疑是不是用了 redis 之类的外部缓存,结果进服务器一查 redis 、memcached 之类的压根儿就没装,所以排除外部缓存。(随后使用 JVM 工具查看也证明了这一点

那既然不是外部缓存,那肯定出在 JVM 上了,要不然就是用了 JVM 缓存,要不然就是内存泄漏什么的。于是我想用 jinfo -flags看一下 JVM 初始参数,JDK 6 竟然还不支持 -flags 。

然后我不知道是不是尝试了 jmap -heap 还是就看了一眼 jmap -help以为不支持 jamp -heap,反正最后我是通过 jconsole来观察的 JVM。一看 JVM 参数明显就是默认没特殊设置过,并且奇怪的是对内存一共采用了 700 多M。700M 和 15G 比,差哪儿去了,没道理啊,问题没出在堆上。

然后我尝试执行 GC 操作,然而并没有任何改善。直到这里,我严重怀疑是出现了内存泄漏了。

于是我执行了 jmap -dump,把堆、线程信息 dump 下来,然后拉到本地分析。不看不知道,一看吓一跳,线程多到令人窒息。

不得不说,有一点他们做的非常好,竟然贴心的给线程编了号,没错,就是有这么多线程 10万多个。于是我们算了一下假设 10分钟请求 300 次,那就是 300 个线程,一小时就是 30 x 6=1800,一天24小时就是1800 x 24=43200,两天多的时间 10万多个线程那就正好对上了,好牛x的样子。

一个线程默认占用空间大小 1M,10万多个线程那就是 10个多G,加上堆内存占用和机器上其他服务的内存占用,内存飙到 15G 就对的上了。

谁的问题谁处理

有问题就找问题就这么难吗,不承认自己的程序有问题是怎么想的呢。

好啊,你们自己不查,我帮你找到问题原因了,满意了吧。

于是,同事理直气壮的把上面那张截图发给他们,但是没有额外说一句话。

下午,微信群里对方发来消息,问题已修改,可以再试试。

然后,好多天过去了,问题没有再出现。

规避问题

有的同学问了,系统能创建10万多个线程吗,有可能的。这篇文章是「你假笨」大神写的 Linux 系统下能创建多少个线程的源码分析 club.perfma.com/article/244…,有兴趣可以上去看一看。

这个问题产生的原因就是线程创建了但是没有销毁,估计是销毁逻辑写的有些问题吧。

抛开逻辑错误不说,使用线程的正确做法是使用线程池,以免带来不必要的性能损耗和这种未加控制、未及时销毁带来的线程无止境创建的问题。

创作不易,小小的赞,大大的暖,快来温暖我。不用客气了,赞我!

我是风筝,公众号「古时的风筝」,一个在程序圈混迹多年,主业 Java,另外 Python、React 也玩儿的很 6 的斜杠开发者。可以在公众号中加我好友,进群里小伙伴交流学习,好多大厂的同学也在群内呦。

Supongo que te gusta

Origin juejin.im/post/5ea0f2a2f265da47aa3f7b0f
Recomendado
Clasificación