Java内存泄漏排查:HashMap频繁使用导致的OOM问题

JAVA基礎之ConcurrentHashMap JAVA基礎之ConcurrentHashMap 简介 ConcurrentHashMap 是 util.concurrent 包的重要成员。本文将结合 Java 内存模型,分析 JDK 源代码,探索 ConcurrentHashMap 高并发的具体实现机制。 由于 ConcurrentHashMap 的源代码实现依赖于 Java 内存模型,所以阅读本文需要读者了解 Java 内存模型。同时,ConcurrentHashMap 的源代码会涉及到散列算法和链表数据结构,所以,读者需要对散列算法和基于链表的数据 阅读详情

前言

作为一名普通的Java开发者,日常开发中经常遇到一些看似简单但实际排查起来非常耗时的问题。这次我遇到了一个比较典型的内存泄漏问题,最终定位到是因为对HashMap的不正确使用导致的OutOfMemoryError(OOM)。这个问题虽然不是特别复杂,但在高并发、大数据量的场景下,它会严重影响系统性能和稳定性。这篇文章将详细记录整个排查过程,包括现象描述、分析思路、代码调试和最终的解决方案。

问题现象

我们项目中有一个定时任务,负责从数据库中查询大量数据并缓存到本地的HashMap中,用于后续业务逻辑处理。在运行一段时间后,应用突然出现内存溢出错误,日志中显示如下信息:

java.lang.OutOfMemoryError: Java heap space

此时JVM的堆内存已经接近上限,GC也无法回收足够的内存。服务器CPU使用率也明显上升,系统变得卡顿甚至无法响应请求。

问题分析

首先,我怀疑是代码中存在内存泄漏,导致对象无法被GC回收。考虑到我们使用了HashMap来缓存数据,我开始重点检查这部分代码。

初步分析发现,我们的缓存逻辑是这样的:每次定时任务执行时,都会从数据库中查询一批新的数据,并将这些数据放入HashMap中,key是某个唯一标识符,value是对应的实体对象。但并没有任何清理机制,也没有设置过期时间,因此这个Map会不断增长,最终导致内存溢出。

为了验证这一假设,我使用JConsole监控JVM的内存情况。观察到老年代(Old Generation)的内存持续上涨,且GC频率增加,但回收的内存却越来越少,说明确实存在不可回收的对象。

排查步骤

第一步:使用JProfiler进行内存分析

我使用JProfiler工具对应用进行了内存快照分析,发现最大的对象类型是com.example.model.DataEntity,而它们都被存储在同一个HashMap中。进一步查看引用链,发现这些对象都是由一个静态的HashMap实例持有,没有被释放。

public class DataCache {
    private static final Map<String, DataEntity> cache = new HashMap<>();

    public static void addData(String key, DataEntity data) {
        cache.put(key, data);
    }

    public static DataEntity getData(String key) {
        return cache.get(key);
    }
}

这个静态Map一旦初始化,就会一直存在,除非应用重启,否则不会被GC回收。由于我们在定时任务中不断往里面添加数据,最终导致内存溢出。

第二步:模拟测试环境重现问题

为了进一步确认问题,我在本地搭建了一个简单的测试环境,模拟定时任务不断向Map中添加数据的情况。运行几分钟后,内存占用迅速上升,最终触发OOM错误。

第三步:优化缓存策略

为了解决这个问题,我决定对缓存策略进行优化。首先,引入了缓存过期机制,使用ConcurrentHashMap结合TimerTask定期清理过期数据。同时,将缓存改为非静态变量,避免长时间驻留。

public class DataCache {
    private final Map<String, DataEntity> cache = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public DataCache() {
        scheduler.scheduleAtFixedRate(this::cleanExpiredData, 1, 1, TimeUnit.MINUTES);
    }

    public void addData(String key, DataEntity data) {
        cache.put(key, data);
    }

    public DataEntity getData(String key) {
        return cache.get(key);
    }

    private void cleanExpiredData() {
        long now = System.currentTimeMillis();
        List<String> keysToRemove = new ArrayList<>();
        for (Map.Entry<String, DataEntity> entry : cache.entrySet()) {
            if (now - entry.getValue().getLastAccessTime() > 60 * 1000) {
                keysToRemove.add(entry.getKey());
            }
        }
        for (String key : keysToRemove) {
            cache.remove(key);
        }
    }
}

通过上述改进,缓存数据得到了有效管理,内存占用稳定了下来。

总结

这次内存泄漏问题虽然看起来简单,但在实际开发中却是很常见的陷阱。尤其是在使用HashMap等集合类时,必须注意其生命周期和内存占用情况。如果长期不清理,很容易导致OOM问题。建议在使用缓存时,尽量使用带有过期机制的数据结构,如ConcurrentHashMap或第三方缓存库(如Caffeine),并在必要时加入监控和告警机制,以便及时发现问题并处理。

此外,对于生产环境的应用,建议定期进行内存分析和GC日志分析,提前发现潜在的内存问题。总之,合理使用集合类、及时清理无用对象是防止内存泄漏的关键。

什么?JDK8 的 ConcurrentHashMap 有 Bug 大家看到标题是不是第一反应,怎么可能 JDK8 的 ConcurrentHsahMap 会有 bug,肯定是个标题党 且慢,的确我们 JDK8 中存在这个 Bug,但是这个 Bug 不影响使用,并且在 JDK12 中对其进行了修复 在这个 JDK 的 Bug 收集论坛上,我们可以看到这个报告指出的是在 ConcurrentHsahMap 进行 addCount() 的时候会有问题存在,我们先看一下具体在 JDK8 和 JDK12 中该方法的体现 JDK8 private f 阅读详情

相关推荐

win11系统ping另一台电脑上VMware虚拟机的IP

我是用了两台电脑,所以刚才遇到一个问题就是两台电脑的IP 在同一局域网内ping不通。于是就找了很多资料,经过坚强的绝望后终于解决了。 下开始解决问题: VMWare提供了三种工作模式:bridged(桥接模式)、NAT(网络地址转换模式)和host-only(主机模式)。 1. bridged(桥接模式)   在这种模式下,VMWare虚拟出来的操作系统就像是局域网中的一台独立主机,它可以访问网内任何一台机器。在桥接模式下,你需要手工为虚拟系统配置IP地址、子网掩码,而且还要和宿主机器处于同一网段,这样虚

qq_42817360的博客 3236

内存泄漏调优案列

内存泄漏

qq_39203337的博客 3014

HashMap面试题

HashMap面试题

T_karine的博客 1029

AD元件库构建及维护之——DbLib公共元件库的使用教程

AD元件库构建及维护之——DbLib元件库的使用教程

qq_43105486的博客 2万+

CentOS7下用FreeRADIUS+AD实现802.1X认证完整指南(附华为交换机配置)

本文提供了在CentOS 7系统上部署FreeRADIUS并与Windows Active Directory集成,以实现企业级802.1X网络认证的完整实战指南。内容涵盖从架构原理、服务器配置(包括Kerberos、Samba Winbind集成)、FreeRADIUS核心设置与AD联动,到华为交换机的详细配置步骤。重点解决了生产环境中常见的高可用、动态VLAN下发及深度排错问题,为企业构建集中、安全的网络准入控制体系提供了经过验证的解决方案。

weixin_29273849的博客 406

ConcurrentHashMap内存泄漏问题

问题背景 上周,同事写了一段ConcurrentHashMap的测试代码,说往map里放了32个元素就内存溢出了,我大致看了一下他的代码及运行的jvm参数,觉得很奇怪,于是就自己捣鼓了一下。首先上一段代码: 1 public class MapTest { 2 3 public static void main(String[] args) { 4 ...

3036

ADRC自抗扰PD+ESO控制(博途SCL源代码)

文章浏览阅读119次。线性自抗扰控制(LADRC)系统算法框图-优快云博客文章浏览阅读335次。NLADRC自抗扰控制从Simulink仿真到PLC控制实现_自抗扰控制器 simulink仿真-优快云博客本文介绍了如何将ADRC自抗扰控制算法从Simulink仿真应用到PLC控制中,包括Simulink框图、TD微分器模型、MATLAB函数的使用、SCL控制代码,以及非线性状态误差反馈控制率的实现。ADRC自抗扰PD+ESO控制(CODESYS测试+完整ST代码)-优快云博客。

RXXW_Dor的博客 1315

【Java】排查Java OOM问题:从定位到解决的全链路指南

Java内存溢出(OOM)排查流程

啊松同学的博客 2345

基于ARKitScenes和YOLOv11的元宇宙3D物体检测系统设计与实现

引言随着元宇宙概念的兴起和增强现实(AR)技术的快速发展,3D物体检测成为了计算机视觉领域的重要研究方向。与传统的2D物体检测不同,3D物体检测不仅需要识别物体类别,还需要估计物体在三维空间中的位置、大小和朝向。本文将详细介绍如何利用ARKitScenes数据集和YOLOv11算法构建一个完整的3D物体检测系统,并提供可视化UI界面。相关工作与技术背景2.1 ARKitScenes数据集介绍ARKitScenes是苹果公司发布的一个大规模的3D场景理解数据集,包含丰富的室内场景数据。

YOLO 411

C#的GDI+绘图详解

/消除锯齿 或 AntiAlias。// 1.在窗体或控件的Paint事件中,用PaintEventArgs e 创建绘图对象 ---- 控件或窗体重绘时。//为控件创建绘图对象。//--------------------以上方法三选一。//2.创建绘图对象 panel1中绘图。

weixin_50920631的博客 3457

JVM OOM问题如何排查和解决

在 Java 开发中,**JVM OOM(OutOfMemoryError)**问题通常是指程序运行时,JVM 无法为对象分配足够的内存空间,导致发生内存溢出的错误。这个问题往往和内存的配置、内存泄漏、或者资源过度使用等因素有关。JVM 中的 OOM 错误主要包括以下几种类型:排查 OOM 问题可以从以下几个角度入手:通过 JVM 参数 来查看堆内存的大小和使用情况。常用的 JVM 参数有:通过这些参数可以定位内存是否足够,堆内存是否被频繁的垃圾回收占满。可以通过一些可视化的工具来监控 JVM 的内存使用情

有时间就写写代码 1413

【2005】人工智能⭐

问题的解答来自于过去的经验而不是规则,这些经验是以案例方式存储的。但是当人们遇到一个新的问题的时候,一般先是回忆,从记忆中找到一个与新的问题相似的案例,然后把该案例的有关信息和知识复用到新问题的求解之中。1、若案例(case)不够充足,而有足够的规则(知识),试问如何构建一个包含有基于案例推理和基于规则推理的推理系统,以使推理效率提高而且总能求得问题的解。一般认为,CBR适合缺乏完备和健全的理论,但又可获取丰富经验的领域,而RBR则适合于对领域有充分的认识,能以完备和健全的形式表示领域理论的场合。

super_mochi1 279

JVM线上OOM问题排查思路与实践

摘要:本文系统介绍了JVM OOM问题的排查方法,涵盖从现象识别到工具使用、内存快照分析的完整流程。重点讲解如何通过jstat监控内存状态、jmap生成堆转储文件,并利用MAT工具定位内存泄漏。通过电商平台真实案例,分析集合类未清理导致的内存泄漏问题,提供使用Guava Cache优化方案的代码示例。最后总结了线上排查禁忌与预防措施,强调配置JVM参数、内存监控和代码评审的重要性。全文提供可落地的技术方案,帮助开发者有效应对OOM问题。 关键词: JVM OOM、内存泄漏、堆转储、MAT分析

没事学AI的博客 957

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

记一次生产程序OOM崩溃的排查解决

(1)不要总觉得JAVA程序OOM离我们很远,简单的一个HashMap,使用不当,程序经常性的往里面put元素,整个map又不会被GC,或者一些for(i=0;;++i)这种死循环代码,里面有类似list.add()操作,都会很容易产生OOM问题!(2)即使是框架层的代码(比如fastjson),也可能会因为一些逻辑不严谨或者使用不当产生一些OOM问题,需要正确使用,比如try {

hu020138的博客 1649

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Java 线上内存溢出(OOM)问题实战排查与解决全流程指南

Arthas是阿里巴巴开源的一款强大的 Java 在线诊断工具,尤其适用于生产环境。实时查看 JVM 内存、线程、GC 状态查看类是从哪个 jar 包加载的动态观察方法是否执行方法执行耗时、异常堆栈分析Dump 堆内存,辅助定位内存泄漏步骤工具说明1jpsjstat确认进程与初步内存状态2实时监控 JVM 内存/GC 状况3导出堆内存快照4VisualVM图形化分析堆内存内容5源码阅读结合代码逻辑分析引用路径步骤内容1. 获取 Heap Dump 文件。

qq_46371374的博客 1672

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

记一次OOM与内存泄漏排查经历

场景:测试环境有个应用容易爆OOM,导致容器也会不断重启,大佬怀疑是内存泄漏导致的,于是对它进行排查 登陆上对应的服务器,安装Arthas Arthas使用指南 查看仪表盘:dashboard 开始压测前 开始压测后: 堆内存比较满,而且是survivor区和eden区占用率飙升严重,右上角垃圾回收次数不断增加,eden区回收占用时间较长 但是还不能确定是否存在内存泄漏,所谓内存泄漏,也就是内存脱离JVM的控制,无法对泄漏的内存进行回收利用,测试方法是手动GC: jcmd XXX(Java应用的进程号

whiteBearClimb的博客 515

如何排查内存溢出(OOM)问题

内存溢出(OOM)排查指南 定位类型:通过日志区分堆溢出、元空间溢出或直接内存溢出 收集信息:使用jmap生成堆转储,MAT分析大对象,jstat监控GC,VisualVM实时观察 常见原因:静态集合膨胀、资源未关闭、缓存无限制、线程未终止 修复方案: 调整JVM参数(堆/元空间大小) 规范代码(及时释放资源、限制缓存) 定期用MAT/VisualVM检查内存 预防措施:设置-XX:+HeapDumpOnOutOfMemoryError自动保存现场,监控系统预警

qq_46130027的博客 956

记一次Orika导致的OOM

场景: 有一个项目运行一段时间后就会出现OOM,下面梳理下寻找问题根源的方法 问题重现 某一天,一个好久没动过的服务崩掉了,top查看进程占用CPU高达700%+ ???? 按照top,jstack一条龙查找导致异常的线程 这里没看到什么异常,把堆文件dump到本地进行分析: ???? 看到HashMap将近占了内存大小的50%。开始寻找项目里哪里用到HashMap 项目里没有找到使用HashMap的地方,转而思考是否是引用的第三方工具包使用不当导致OOM 看到有很多set方法和map方法

baidu_35166149的博客 885

Java堆内存溢出深度排查:从OOM报错到内存泄漏根治实战

Java堆内存是JVM运行时数据区的核心组成部分,用于存储所有对象实例和数组。其工作原理基于分代收集理论,通过新生代和老年代的划分配合垃圾回收机制管理对象生命周期。合理管理堆内存对保障应用稳定性和性能至关重要,能有效避免因内存不足导致的系统崩溃。在实际工程实践中,内存泄漏是引发堆空间不足的常见原因,表现为对象因不当引用无法被回收。通过分析堆转储文件,可以定位到具体的泄漏点,例如静态集合持有过期对象。结合实时监控与性能剖析工具,开发者能够系统性诊断内存问题,优化代码实现与架构设计,最终在微服务、大数据处理等高

weixin_34174105的博客 344

线上OOM问题排查全过程实战指南

线上OOM问题排查实战指南 摘要 本文记录了一次线上OOM问题的完整排查过程。通过监控告警发现JVM堆内存使用率超过90%,立即采取以下措施: 紧急响应:使用jmap导出堆快照,jstat分析GC情况,发现老年代几乎全满且Full GC频繁 问题定位:通过MAT工具分析堆快照,发现45,123个SysUser对象被静态HashMap缓存且无过期机制 解决方案: 短期修复:改用WeakHashMap或带过期时间的缓存 长期方案:迁移到Spring Cache + Redis 工具清单:提供jps/jstat/

ARUNNE的博客 407

java OOM问题分析排查

java服务OOM最常见的原因: 内存分配过小,而正常业务需要使用更大的内存; 某一个对象被频繁申请,确没有释放,内存不断泄露,导致内存耗尽; 某一个资源被不断申请,系统资源耗尽,如:不断创建线程,不断发起网路连接。 排查过程: 1、jmap -heap pid查看堆内存分配: jmap -heap -pid确认内存本身是否分配过小,可以看到新生代、老年代的参数配置。 C:\Users\Lenovo>jmap -heap 19676 Attaching to process ID ...

weixin_40482816的博客 1041

一次 OOM 事故的完整排查:从报警到根因的全过程复盘

《Java线上OOM事故排查实录》摘要:某Java服务突发OOM崩溃,堆内存溢出导致进程退出。通过HeapDump分析发现静态HashMap占用70%内存,无上限缓存是根本原因。不同于常见认知,OOM往往不是内存不足,而是代码缺陷导致:静态变量强引用使GC失效,无淘汰策略的"伪缓存"成为定时炸弹。解决方案包括改用专业缓存工具(如Caffeine)、开启HeapDump监控、设置内存告警。该案例揭示了OOM排查的核心方法论:先确定类型,分析GC日志,通过内存快照定位引用链,最终针对性修复。

weixin_38717458的博客 842

两个OOM Cases排查过程的分享

分享一下两个OOM Cases的查找过程,一个应用是Native OOM;另外一个应用其实没有OOM,只是每隔一段时间就会出现频繁FGC的现象,OOM的查找已经具备了不错的工具,但有些时候还是会出现很难查的现象,希望这两个排查过程的分享能给需要的同学带来一些帮助。 Native OOM的排查Case 之前的几个PPT里我都说到了,目前查找Native OOM最好的方法就是用google per

沉底的石头 987

Java OOM问题排查与内存泄漏分析实战

Java虚拟机(JVM)内存管理是保证应用稳定运行的核心机制,其中OutOfMemoryError(OOM)是最常见的内存异常。理解OOM的产生原理需要从JVM内存模型入手,包括堆内存、元空间和直接内存等区域。通过工具链如Arthas、MAT等可以进行内存泄漏分析,识别静态集合累积、未关闭资源等典型问题模式。在云原生环境下,容器内存限制与JVM参数配置的适配尤为关键。掌握这些排查技术能有效提升系统稳定性,应对高并发场景下的内存挑战。

weixin_34198453的博客 419

JVM问题排查

cpu飙升可能的原因大概为:代码存在死循环,导致消耗cpu;代码一直在创建大对象,导致频繁GC,这个时候内存占用率也会很高;

yangnk的技术记录 1996
上一篇: Java全栈开发实战:从基础到微服务的深度探索
下一篇: 从Java全栈开发到微服务架构:一次真实的面试对话
叫我阿柒啊
博客等级 码龄9年 2433粉丝 2369原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值