0
点赞
收藏
分享

微信扫一扫

项目开发流程

静悠 2024-05-04 阅读 9
jvm

内存调优

什么是内存泄漏、内存泄漏?

  1. 内存泄漏:在Java中如果不再使用一个对象,但是该对象依然在GC ROOT的引用链上,这个对象就不会被垃圾回收器回收。
  2. 内存溢出:内存的使用量超过了Java虚拟机可以分配的上限,最终产生了内存溢出OutOfMemory的错误。

内存泄漏的原因?

  1. 持续的内存泄漏:内存泄漏持续发生,不可被回收同时不再使用的内存越来越多,就像滚雪球一样雪球越滚越大,最终内存被消耗完无法分配更多的内存去使用,导致内存溢出。
  2. 并发请求问题:用户通过发送请求向Java应用获取数据,正常情况下Java应用将数据返回之后,这部分数据就可以在内存中被释放掉。但是由于用户的并发请求量有可能很大,同时处理数据的时间很长,导致大量的数据存在于内存中,最终超过了内存的上限,导致内存溢出。

内存泄漏原因

代码中

  1. equals()和hashCode() 导致的内存泄漏。没有重写正确的这两个方法。在使用HashMap的场景下,如果使用这个类对象作为key,HashMap在判断Key是否已经存在时会使用这些方法,如果重写方式不正确,会导致相同的数据被保存多份。
  2. 内部类引用外部类。非静态的内部类默认会持有外部类,垃圾回收时无法回收外部类。使用静态内部类,或静态方法。
  3. ThreadLocal的使用。手动创建的线程会自动回收,线程池创建的线程不会自动回收。需要调用ThreadLocal中的remove方法清理对象。参考问题 ThreadLocal中为什么要使用弱引用。
  4. String的intern方法。把字符串加入字符串常量池。
  5. 通过静态字段保存对象。大量数据在静态变量中被长期引用,数据就不会释放。减少保存在静态变量中,若不再使用则必须删除或设置为null。单例模式中,尽量使用懒加载,而不是立即加载。@Lazy。Bean中不要长期存放大对象,如果是缓存,设置过期时间。
  6. 资源没有正常关闭。不一定出现内存泄漏,会导致close方法不被执行。Java7开始,申请资源放在try()里面可以用于自动关闭资源。

并发中

通过发送请求向Java应用获取数据,正常情况下数据返回后,即可释放数据。当并发量很大,同时处理数据的时间长,导致大量的数据存在于内存中,导致内存溢出。

内存泄漏的解决方案

  1. 发现问题,通过监控工具尽可能尽早地发现内存慢慢变大的现象。
  2. 诊断原因,通过分析内存快照或者在线分析方法调用过程,诊断问题产生的根源,定位到出现问题的源代码。MAT打开hprof文件。
  3. 修复源代码中的问题,如代码bug、技术方案不合理、业务设计不合理等等。
  4. 在测试环境验证问题是否已经解决,最后发布上线。
-XX:+HeapDumpOnOutOfMemoryError #OOM时打印内存快照
-XX:HeapDumpPath=D:\jvm\dump\test1.hprof
-XX:+HeapDumpBeforeFullGC  #可以在FullGC之前就生成内存快照

jmap -dump:live #命令导出内存快照
heapdump #arthas中

MAT内存泄漏检测的原理

支配树。

在这里插入图片描述

在这里插入图片描述

监控Java内存的常用工具

JDK自带的命令行工具:

jps 查看java进程,打印main方法所在类名和进程id

jmap 生成堆内存快照;打印类的直方图

第三方工具:

  1. VisualVM
  2. Arthas
  3. MAT 堆内存分析工具
  4. Prometheus + Grafana

在线定位

  1. Jmeter插件,gc插件。
  2. arthas stack命令在线定位步骤,可以定位类。
  3. btrace脚本,可以指定类,监控的方法。灵活性高。

内存溢出案例

  1. 分页查询文章接口:单个文章对象占用内存量较大。限制单词访问条数;不需要获取文章内容;高峰期对微服务限流保护。
  2. Mybatis:判断ids是否存在id的接口。foreach进行sql拼接时,会在内存中创建对象,占用空间。限制参数中最大的id个数;将id缓存到redis或内存缓存中,通过缓存校验。
  3. 导出大文件:excel文件导出如果使用POI的XSSFWorkbook,在大数据量下占用大量内存。使用poi的SXSSFWorkbook;hutool中BigExcelWriter;easy excel。
  4. ThreadLoacl:在拦截器中,ThreadLocal清理的代码被错误的放在postHandle中,如果接口发生了异常,这段代码不会调用到,这样就产生了内存泄漏,将其移动到afterCompletion就可以了。
  5. 文章内容审核接口:SpringBoot中@Async注解异步审核;生产者消费者模式队列持久化到数据库;mq消息队列,保存文章数据
举报

相关推荐

0 条评论