Java内存占用过高问题分析

  1. 这里我们创建一个springboot项目, 然后随便写一个contoller, 在这个controller中定义一个List集合, 然后再初始化的时候让集合中10万个字符串, 然后部署并启动项目(这里为了贴近实战, 我是在centos中启动的项目)

  2. 进入系统, 使用top命令显示系统中的进程信息, 然后点击H(大写), 以内存排序

    这时我们看到, Java程序占用了5.5%的内存

    前面VIRT列表示的是java申请了多少内存, RES表示实际使用了多少内存 这里的单位是k

    在这里主要是看一下概率情况, 同时拿到java程序的进程编号

  3. jdk为我们提供了jmap工具, 这个工具可以帮助我们扫描java进行当前的内存情况

    jmap的功能很多, 这里我们主要使用这个工具查看占用内存最多的类型是什么

    # 这里稍微解释一下, | 的作用是拼接多个命令, |后面的命令利用前面的命令的执行结果继续执行
    jmap -histo:live 2249762 | head -20
    

    num : 表示行号, #instances 表示jvm中总共有这个数量的实例对象 #bytes表示这些实例对象总共占用了多少内存(单位byte)

    我们看到, jvm中总共有124240个字符串对象, 显然不太合理

    到这里, 我们其实仅仅能知道jvm中出现了大量不正常的字符串对象, 至于这些字符串在什么位置, 什么原因产生的还是一无所知

  4. 接下来, 我们需要具体看看是哪些字符串占用了内存, 并且找出在引用关系, 看看是哪些对象在使用这些字符串

    jmap智能粗略的分析内存问题, 如果想要更细致的分析内存,比如说分析对象之间的引用关系, 可以使用jhat工具

    这个工具就需要们先将jvm内存详细信息导出到一个文件中,在使用jhat分析

    使用 jmap -dump:live,file=heap.bin 进程编号 命令, 将jvm内存导出到一个heap.bin文件中

    # 导出jvm结构
    jmap -dump:live,file=heap.bin 2254420
    

    # 使用jhat分析文件, jhat回启动一个服务器, 让我们可以在网页上查看信息, 默认端口是7000
    # 如果想要修改端口, 可以使用 -port 端口号的方式修改 jhat -port 8088 heap.bin
    jhat heap.bin
    

  5. 接下来我们就可以在浏览器中查看了 , 这里展示的内存中的所有对象的类型

    注意, 默认显示的是不包含jdk原生的类型的, 所以, String类型这里显示不出来, 需要将页面滑动到最下面

    All classes including platform: 显示所有的类型,包含java原生的类型

    Show all members of the rootset: 显示所有的根节点

    Show instance counts for all classes (including platform): 显示所有的类型的实例对象数量,包含jdk原生的类型

    Show instance counts for all classes (excluding platform): 显示所有的类型的实例对象数量,不包含jdk原生的类型

    Show heap histogram : 显示堆内存的统计信息, 其实这里就是上面 jmap -histo:live 命令展示的结果

    Show finalizer summary: 实现即将被回收的对象的信息

    Execute Object Query Language (OQL) query: 跳转到oql执行页面, 可以让我们使用类似于sql语句的形式查询对象.

  6. 点击 Show instance counts for all classes (including platform), 显示所有类型的对象信息

    这里我们看到, String类型的对象总共有128002个对象, 我们点击去就可以看到具体的字符串对象信息了. 这里我们看到有许多重复的字符串信息, 大概就是问题所在

    选择其中一个对象,点击进去, 着重显示的位置表示是当前对象被那个对象引用着, 这里能看到, 当前字符串被一个Object类型的数组引用着

    我们可以通过这个关系, 一层层的往上找, 知道找到们熟悉的对象

    我们点击之后, 可以进入到这个数组的详情页面, 这里有一个问题, 因为数组中的元素特别多, 当我们进入到数组的详情页面之后, 他的引用关系是显示在页面的最下面的, 让我们查看起来非常麻烦, 而且,如果数据量过多(>百万), 很有可能回引起页面崩溃.

    所以, 这里我们可以使用oql语句直接查询

    在主页上有进入oql语句的输入页面

    点击查询的结果, 进入到ArrayList集合中, 我们终于看到了一个熟悉的类型: MyController

    也就是说, 这个包含大量字符串对象的数组, 其实MyController中的ArrayList集合中的数据, 至此, 我么便可以结合源码, 进一步查询问题的所在了

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值