前面排查内存溢出,是通过生成的内存快照,当内存较大时,此方法生成、导出快照慢(主要生成堆内存快照的时候,会耽误服务器去处理用户发来的请求,影响体验),且在本地用MAT分析快照文件时,对本地内存大小也有要求(快照的1.5-2倍)。下面用在线定位的方式。

0、补充

将这个插件放到Jmeter的lib目录下:

在这里插入图片描述

将这两个插件放到lib/ext目录下:

在这里插入图片描述

打开Jmeter:

在这里插入图片描述

以上三个分别为:

  • 活跃线程数
  • 当前请求的响应时长
  • 每分钟执行的事务数

添加一个响应时长的监听器,在不去生成内存快照的时候,响应时间较短:

在这里插入图片描述

再向服务器上执行jamp生成快照,期间发现响应时间明显变长(本来20ms的,成了500+ms)

在这里插入图片描述

下面不用这种导出快照的方式,用在线定位,这种方式对用户请求的影响较小,但同时无法查看到像快照文件那样详细的内存信息。

1、jmap + Arthas

执行

//你服务运行的进程ID
jmap -histo:live 进程ID > 文件名

将内存中存活对象以直方图的形式保存到文件中,如下图,相比之前导出快照导致用户响应时长变成500ms,这里约140ms
在这里插入图片描述

在直方图文件中找到内存占用最多的对象(关注自己写的类),即嫌疑最大的对象。使用arthas的stack命令,追踪对象创建的方法被调用的链路。

stack com.plat.Controller.DemoController queryMethod  //方法名 类名

2、BTrace

用于线上运行系统的方法追踪,侵入小,对系统性能影响小。

官方地址:https://github.com/btraceio/btrace/releases/latest

解压后,simple目录下是一些脚本例子,可模仿。下面编写一个BTrace脚本:

@BTrace   //声明这是一个BTrace脚本
public class TracingUserEntity {

	@OnMethod(
		clazz="com.plat.entity.UserEntity",    //指定要监控的类
		method="/.*/"			//正则表达式,两个/表示开始和结束,中间的.*代表监控所有的方法
	)
	public static void traceExecute(){    //该方法在条件满足的时候就会触发
		jstack();   //调用BTrace内置的方法,打印所监控的方法被调用时的栈信息
	}
}

将btrace工具上传到服务器并添加至环境变量

vi /etc/profile

在这里插入图片描述
将自定义的脚本也上传到系统所在服务器,运行:

btrace 进程ID 脚本文件名

在这里插入图片描述

3、总结

内存泄漏和内存溢出:

  • 内存泄漏:不再使用一个对象了,但其在GC Root引用链上,不会被回收器回收,白占空间
  • 内存溢出:内存的使用量超出了JVM分配的上限,OutOfMemory

内存溢出的产生原因:

  • 持续的内存泄漏,导致可用空间越来越少。最后来个请求,彻底压垮
  • 并发请求,正常Java服务返回数据后,相关对象在内存中被释放,但当并发请求下,或者一次请求很大的数据量下,处理数据的时间变量,半天没返回,导致大量数据对象在内存中,进而OOM
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐