Su的技术博客

  • 首页
  • 原创
  • 视频
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • AI
  • Other
  • 工具
    • AI工具集
    • 工具清单
    • JSON在线格式化
    • JSON在线比较
    • SQL在线格式化
  • 打赏
  • 关于
路很长,又很短
  1. 首页
  2. 事故复盘
  3. 正文
                           

【原创】实战:一次疑似内存泄漏的问题排查

2024-11-06 1124点热度 0人点赞 0条评论

1、问题背景

我的博客网站https://blog.verysu.com,有兴趣的可以访问下。

最近服务器到期等因素,进行了迁移。租了其它的外国厂商,但是由于资费问题,购买了1.5G 内存的服务器(现)。因为原本用惯了4G内存的服务器(原),现在压缩成这样,似乎不太能支持我的使用,囧!

现在就来说下blog服务分配的内存情况:

原:4G 内存,分配给blog,1.5G。

现:1.5G内存,分配给blog,500M。

由于此次调整,原本以为资源需求压力会更大。实际上应该不会,仔细想想,blog也没多少内容的。那么根据此次调整之后,已经出现了2次OutOfMemoryError了。

由于JVM参数配置有加上-XX:+HeapDumpOnOutOfMemoryError,所以出现OutOfMemoryError时会将堆栈输出到指定的文件,这样可以方便以后排查问题。

OS:CentOS7

Web容器:Tomcat 8

ORM:Hibernate3

数据库:MySQL5

 

2、问题解决过程

2.1 诊断排查出现内存泄漏对象

实战:一次疑似内存泄漏的问题排查

这个文件占用了差不多535M,说明里面的对象占用空间很大。这里我使用了MAT工具来排查。

实战:一次疑似内存泄漏的问题排查

 

1)Histogram (可以查看每个类的实例(即对象)的数量和大小)

实战:一次疑似内存泄漏的问题排查

通过Histogram图,我们初步看出,实际上跟我们自己的代码好像是没有关系,因为这里没找到我们对应的包名和类名。不过可以看到一些疑惑就是Tomcat和mysql相关的类占用了很大内存。

 

2)Dominator Tree(列出Heap Dump中处于活跃状态中的最大的几个对象,默认按 retained size进行排序)

实战:一次疑似内存泄漏的问题排查

从这里可以更加明确是哪些对象占用了大部分资源了,似乎也是跟Tomcat和mysql有关。

 

3)Top Consumer(按类、类加载器和包分别进行查询,并以饼图的方式列出最大的几个对象)

实战:一次疑似内存泄漏的问题排查

通过上面这个饼图,我们更加明确的是哪些对象占用了大部分资源。其它一些视图这里就不展开了。

 

小结:上面MAT的各种视图表明,并不是说占用资源大的对象是就是内存泄漏的罪魁祸首,它这里只是做了个统计,方便你观察和发现问题,只是提示你可能这些对象存在泄漏的可能性。

 

2.2 诊断排查占用大资源内因

由上面的图中,我从TaskThread这个类入手:

实战:一次疑似内存泄漏的问题排查

发现主要占用的资源在StatefulPersistenceContext这个类,很明显这个是Hibernate持久化相关的。

实战:一次疑似内存泄漏的问题排查

查看下类的注释,大致意思是:

PersistenceContext表示Hibernate正在跟踪的持久化“内容”的状态。这包括持久实体、集合以及生成的代理。

SessionImpl和PersistentContext之间应该是一对一的对应关系。SessionImpl使用PersistentContext来跟踪其上下文的当前状态。事件监听器使用PersistentContext来执行处理。

因为Hibernate的一级缓存就是在Session层面上,所以StatefulPersistenceContext跟一级缓存有关系,网上有些资料也有说StatefulPersistenceContext存在问题可能造成内存泄漏等原因。

可以在使用完Session时进行clear清除。这样就能防止占用过大资源,但是,使用一级缓存是能够大大的增强性能,如果这么做的话,似乎有违背Hibernate的设计初衷,因此,这里我们不能采取这种做法。

 

继续往下挖,看这里面存放的是具体什么对象吧!

实战:一次疑似内存泄漏的问题排查

从这里可以看出,持久化的主要对象实体是ShareArticle,并且有1706个实体之多!~,这里只是TaskThread这个线程所持有这么多的实体,要知道下面还有几个大对象TaskThread,里面也是有包含这些的,所以不仅仅1千个多实体。

 

2.3 找出问题根源(“真凶”)

实战:一次疑似内存泄漏的问题排查

看到这个实体的每个字段,才知道问题出现在哪!这张表有一个content字段,类型是mediumtext,存放文章内容。所以一旦加载到内存里,自然的需要占用大部分资源了。

找到问题的点在哪了,接下来就得看怎么优化,毕竟在资源急缺的我,需要优化下当前的服务了。

 

2.4 解决问题,优化!优化!

2.4.1 优化之一:查询不返回content字段

特别是哪些查询列表相关的。这能大大的减少占用内存。因为有些查询List结果实际上是没有使用到content字段,再次查询出来也是一种浪费。

说下这个过程吧,由于使用的是Hibernate,虽说有其优点,但是使用起来极其不灵活!在公司用惯了Mybatis,才知道Mybatis的好,哈哈!

 

2.4.2 优化之二:只查询需要的字段

在查询当前文章的上下文时,基本上也是不用用到content字段,这里只需要返回id和title,即可。其实跟上面2.4.1的类似。

 

2.4.3 优化之三:延迟加载指定字段

我们知道,Hibernate在一对多、多对多等关系中,是支持延迟加载的。查资料发现Hibernate3也能支持指定字段进行延迟加载,在需要的时候再次去查询数据库指定的字段再返回。

所以就动手干!但是也遇到使用时出现不生效,资料表明需要再次使用字节码进行增强才能正常使用。具体操作可以看下下面这篇文字:https://blog.verysu.com/article/414

 

小结:经过上面的优化,服务再也不会出现OutOfMemeryError了,而且资源占用也大幅度降低。

 

3、总结(经验与优化)

1)针对占用资源多的,是否能够不存在数据库,比如生成静态HTML文件,访问的时候直接包含在页面直接返回,这样能快速返回,占用内存少,提升性能。

2)针对大字段(占用资源大),没用到时不返回。

3)只返回需要的字段,在SQL优化的上必有,这样也能提升mysql的吞吐量,也不会浪费资源。

4)如果追求灵活性,ORM建议使用mybatis,毕竟互联网公司基本用它。Hibernate更适合在企业系统里面使用。

5)如果已经使用了Hibernate了,可以增加字段延迟加载机制,进而在需要的时候再去查询。

 

好了,为了写这篇文章,花了两个多小时,觉得不错的话,点个赞呗^_^!

 

推荐工具1:

MAT:Eclipse Memory Analyzer  下载地址:

http://www.eclipse.org/mat/

推荐工具2:

IBM HeapAnalyzer 下载地址:

https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=4544bafe-c7a2-455f-9d43-eb866ea60091

 

参考资料:

Java程序内存分析:使用mat工具分析内存占用

  https://www.cnblogs.com/AloneSword/p/3821569.html

Shallow Heap 和 Retained Heap的区别

  https://blog.csdn.net/a740169405/article/details/53610689

Shallow heap & Retained heap  

https://www.jianshu.com/p/0deac3af0f45

Java堆:Shallow Size和Retained Size

https://blog.csdn.net/iteye_18480/article/details/82514130

Hibernate 一级缓存导致某保险公司核心系统Weblogic中间件内存溢出的故障诊断 https://blog.csdn.net/zhouleiblog/article/details/82834331

Hibernate 一级缓存的陷阱 

https://www.cnblogs.com/hyl8218/p/5076338.html

 

本文仅供学习!所有权归属原作者。侵删!文章来源: 搬运工来架构 -cocodroid :http://mp.weixin.qq.com/s/pVVOknOFzQ5WvrECj_EWFw

更多文章:

  1. JVM 内存分析神器 MAT: Shallow Heap Vs Retained Heap 你理解的对吗?
  2. JVM 内存分析工具 MAT 的深度讲解与实践——进阶篇(长文)
  3. JVM 内存分析工具 MAT 的深度讲解与实践——入门篇
  4. 殷浩详解DDD系列 第一讲 - Domain Primitive
  5. JVM 内存分析神器 MAT: Incoming Vs Outgoing References 你真的了解吗?
  6. 生产环境JVM崩溃问题排查解决
  7. JVM 内存分析工具 MAT 的深度讲解与实践——高阶篇
  8. ElasticSearch之各大版本演进,发布8.0.0 Alpha 2版本
  9. Spring中@Autowired和@Inject注解的区别?
  10. 手把手教你实战TDD
标签: 原创 JVM 线上事故 线上问题 Java Hibernate MAT 内存泄露 延迟加载
最后更新:2024-11-06

Cocodroid

专注Java后端,分享技术。

打赏 点赞
< 上一篇
广告
文章目录
  • 1、问题背景
  • 2、问题解决过程
    • 2.1 诊断排查出现内存泄漏对象
    • 2.2 诊断排查占用大资源内因
    • 2.3 找出问题根源(“真凶”)
    • 2.4 解决问题,优化!优化!
  • 3、总结(经验与优化)
最新 热点 推荐
最新 热点 推荐
Anthropic Code with Claude 开发者大会:开启 AI Agent 新时代 视频笔记-微服务架构P4:必懂5种设计模式 视频笔记:微服务架构P4 设计模式:每服务数据库、API 网关和事件驱动架构 干货 | 论Elasticsearch数据建模的重要性 马蜂窝消息总线——面向业务的消息服务设计 基于 MySQL Binlog 实现可配置的异构数据同步 视频笔记:Google发布Agent2Agent协议 视频笔记:什么是微服务,为什么是微服务?
基于 MySQL Binlog 实现可配置的异构数据同步马蜂窝消息总线——面向业务的消息服务设计视频笔记:微服务架构P4 设计模式:每服务数据库、API 网关和事件驱动架构干货 | 论Elasticsearch数据建模的重要性视频笔记-微服务架构P4:必懂5种设计模式Anthropic Code with Claude 开发者大会:开启 AI Agent 新时代
记一次堆内外内存问题的排查和优化 系统设计 | 系统设计中需要考虑到的时间问题 殷浩详解DDD 第三讲 - Repository模式 系统设计 | 如何管理应用系统中的配置? 【进阶玩法】策略+责任链+组合实现合同签章 系统设计 | 搭建持续集成和部署流水线 视频笔记:什么是微服务,为什么是微服务? Spring Boot 与 Quarkus 对比解析:谁才是你的最佳Java框架?

CRUD (1) Event Sourcing (1) graphql (1) id (1) NoSQL (1) quarkus (1) rest (1) RocketMQ (2) Spring Boot (1) zk (1) zookeeper (1) 上下文 (1) 事务消息 (1) 二级缓存 (1) 值对象 (1) 关系数据库 (1) 分布式缓存 (1) 原子性 (1) 唯一ID (1) 商品 (1) 多对多 (1) 子域 (1) 字符集 (1) 客户端心跳 (1) 幂等 (2) 干货 (1) 并发 (1) 应用场景 (1) 应用架构图 (1) 康威定律 (2) 异步复制 (1) 微服务架构 (3) 总体方案 (1) 技术方案 (2) 技术架构 (2) 技术架构图 (1) 技能 (1) 持续集成 (1) 支撑域 (1) 故障恢复 (1) 数据架构图 (1) 方案选型 (1) 日记 (1) 服务发现 (1) 服务治理 (1) 服务注册 (2) 机房 (1) 核心域 (1) 泄漏 (1) 洋葱架构 (1) 消息队列 (5) 源码剖析 (1) 灰度发布 (1) 熔断 (1) 生态 (1) 画图工具 (1) 研发团队 (1) 线程 (2) 组织架构 (1) 缓存架构 (1) 编码 (1) 视频 (20) 读写分离 (1) 贵州 (1) 软件设计 (1) 迁移 (1) 通用域 (1) 集群化 (1) 雪花算法 (1) 顺序消息 (1)

推荐链接🔗
  • AI工具集
  • 工具箱🛠️

COPYRIGHT © 2014-2025 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2