今天碰到一个问题,系统后台首页数据不展示了。我使用浏览器的开发者功能,找到api,确实服务器返回给浏览器的结果是空数据。然后我顺藤摸瓜找到了这个api的代码,结果发现又是使用的内存缓存。
public class TaskStatic {
public static List<PostbackLogBean> payoutlistAffHour;
}
所以我就想,居然没有数据,那我就看看缓存对象payoutlistAffHour是否有数据。
此时,我需要一个强大的工具,I need a powerful tool !我需要查看payoutlistAffHour这个List的size值。注意,如果你用VisualVM工具分析,你是得不到TaskStatic这个对象的,因为TaskStatic根本没有被实例化,只是用到TaskStatic类的静态字段,所以TaskStatic在堆中不存在实例对象。
dump堆内存数据,下载到本地
在服务器上dump堆内存信息需要的几条命令。
第一条:sudo su
第二条:jps
第三条:ps -ef|grep java
第四条:jmap -dump:live,file=current_object_in_memory_info.dump pid
第一条sudo命令用于切换到root用户,因为项目是使用sh脚步启动的,如果使用登陆用户直接运行jps命令是获取不到java进程id的。但有时候jps命令也不是很管用,可能是我不懂它的更加强大的用法吧。如果有多个java进程的名称是一样的时候,运行jps命令看到的内容是这样的。
>jps
>1111 main
>2222 main
>3333 main
从上面的输出中我们无法得知到底谁是谁,哪个才是我们想要的进程。这种情况下可以使用第三条命令:ps -ef|grep java。这条命令输出的信息足以让我们找出目标进程的进程id,除此之外还能看到启动参数,即传递给main方法的参数。
最后一条命令是用于dump堆内存信息的,其中file=current_object_in_memory_info.dump 是用于存储堆内存信息的文件,文件名为current_object_in_memory_info.dump,可以自己随便取。pid则是目标进程的进程id。执行完这条指令之后将文件下载到本机电脑,不要在远程服务器上分析,免得增加服务器压力。如current_object_in_memory_info.dump文件。
通过 Jhat分析目标对象
以前我都是使用VisualVM或者JProfiler工具来分析,但是今天我发现了Jhat其实也不赖,而且帮助我解决了一个棘手的问题。问题已经在文章开头给出,现在来看看我是如何借助JHat的强大功能查看类型为List的静态字段的大小。
打开终端,进入到,从服务器上下载下来的dump堆内存信息文件所在目录,如current_object_on_memory.dump,所在的目录。然后执行下面这条jhat指令。
>jhat current_object_on_memory.dump
等待jhat执行成功后,就可以在浏览器中输入“http://localhost:7000”访问jhat,查看jhat的分析结果。得要有目的性的查看,按“command+f”输入目标对象,最好输入包名,可以快速准确定位到目标。如下图。
找到目标类后,点击该类名,跳转到class详情页。
class详情页,列出了该类的父类、加载它的类加载器等信息,如果该类有子类则还会列出所有子类。现在我要重点关注的是“Instance Data Members” 这部分的数据,可理解为类的实例的字段数据,包括静态字段。
从上图中可以找到payoutlistAffHour字段,该字段是一个ArrayList类型,没有错。有下划线说明是个链接,点击跳转到该字段的详情数据页。
非常巧,也非常的强大!上图对象详情页的size就是该静态List的大小,很显然并没有数据。用Jhat来分析对象在堆中的信息非常合适,你get到了吗?
既然内存中没有对应的数据,那么病根就可以追溯到上一层了,是哪里给这个静态字段赋的值。当然,这是题外话了。
https://mp.weixin.qq.com/s/q_0ToceHxlxTfS0_r-Qzhg