GC overhead limit exceeded内存溢出解决

做了一个在线爬取网站的项目,线上的项目跑了一天后,突然发现没有新数据进来了。

后台查看日志,发现报错:

java.lang.OutOfMemoryError: GC overhead limit exceeded。

造成这个现象的原因是因为,GC时间消耗的较多。

查看了一下代码,发现在入库的sql语句中大量使用String sql="select * from table";sql = sql+"where 1=1 ";这种类似的语句。

造成大量的堆内存的创建,将Sting修改为StringBuffer解决这个问题。

下面记录解决过程:

暂时解决这个问题,方法是,增加参数,-XX:-UseGCOverheadLimit,关闭这个特性,同时增加heap大小,-Xmx1024m。

接下来查找原因:

jmap -heap 32658

Heap Configuration://配置
   MinHeapFreeRatio = 0
   MaxHeapFreeRatio = 100
   MaxHeapSize      = 994050048 (948.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)
   G1HeapRegionSize = 0 (0.0MB)


Heap Usage:
PS Young Generation
Eden Space://伊甸园区
   capacity = 234356736 (223.5MB)
   used     = 80175472 (76.46128845214844MB)
   free     = 154181264 (147.03871154785156MB)
   34.21086731639751% used
From Space://年轻代(幸存者乐园1)
   capacity = 43515904 (41.5MB)
   used     = 6920760 (6.600151062011719MB)
   free     = 36595144 (34.89984893798828MB)
   15.90397846267884% used
To Space://年轻代(幸存者乐园2)
   capacity = 41943040 (40.0MB)
   used     = 0 (0.0MB)
   free     = 41943040 (40.0MB)
   0.0% used
PS Old Generation//老年代
   capacity = 113246208 (108.0MB)
   used     = 80847952 (77.10261535644531MB)
   free     = 32398256 (30.897384643554688MB)
   71.39131051522715% used
PS Perm Generation//永久代
   capacity = 85983232 (82.0MB)
   used     = 63842008 (60.884483337402344MB)
   free     = 22141224 (21.115516662597656MB)

   74.24936992366139% used

尴尬,犯了这个低级错误。

以后写代码之前一定要多思考,想清楚了再动手。



<think>嗯,用户问的是如何解决Java中的GC overhead limit exceeded错误。首先,我需要回忆一下这个错误的具体原因。根据之前学过的知识,这个错误通常发生在Java虚拟机(JVM)在垃圾回收(GC)上花费了太多时间,但回收的内存却很少,导致应用性能严重下降。JVM默认会抛出这个错误来防止应用陷入无休止的GC循环中。 接下来,我得整理解决方法。用户提供的引用里提到了几个方法,比如增加堆内存、优化代码、分析内存泄漏、调整JVM参数等。需要把这些方法有条理地呈现出来。同时,还要考虑用户可能的实际情况,比如他们可能不知道如何生成分析GC日志,或者如何调整JVM参数,所以步骤需要详细一些。 首先,检查错误日志,确认是GC overhead limit exceeded。然后,增加堆内存可能是个快速缓解的办法,但治标不治本。优化代码,比如避免内存泄漏减少对象创建,是关键。比如,注意集合的使用,及时清理无用的对象,使用更高效的数据结构。 接下来是生成分析GC日志,用户可能需要配置JVM参数来生成日志堆转储文件,这需要给出具体的参数示例,比如-XX:+HeapDumpOnOutOfMemoryError。然后,使用工具如Eclipse MAT或VisualVM来分析内存泄漏。 调整JVM参数方面,可以禁用GC overhead限制,但这是个临时措施,不建议长期使用。另外,选择合适的垃圾收集器,比如G1GC,可能更适合处理大堆内存减少停顿时间。 最后,升级JVM版本也是一个可能的解决方案,因为新版本可能在GC算法上有改进,优化了性能。 需要确保回答结构清晰,分步骤说明,并且引用提供的资料来支持建议,比如引用[1]提到的禁用GC overhead limit的参数,以及引用[2]中关于生成GC日志堆转储的方法。同时,提醒用户禁用限制只是权宜之计,真正的解决还需要优化代码内存使用。 可能用户是开发人员,遇到生产环境的问题,需要快速解决,但也要长期方案。因此,回答中需要兼顾临时措施根本解决方法。确保语言通俗易懂,步骤明确,让用户能一步步操作,比如如何添加JVM参数,如何使用分析工具等。 最后,生成相关问题,可能涉及如何分析内存泄漏,如何调整JVM参数,或者GC的工作原理,这些都可以作为相关问题列出,帮助用户进一步学习。</think>### 如何解决 Java GC overhead limit exceeded 错误? #### 错误原因分析 `GC overhead limit exceeded` 表示 JVM 花费超过 **98% 的时间**进行垃圾回收,但仅释放了 **不到 2% 的堆内存**。此错误是 JVM 的保护机制,防止应用陷入无限 GC 循环[^1]。 --- ### 解决方案步骤 #### 1. 确认错误根源 - **查看日志**:通过 `gc.log` 堆转储文件 `dump.hprof` 定位内存泄漏点 - **生成日志的 JVM 参数**: ```bash -Xloggc:./temp/gc.log # 指定 GC 日志路径 -XX:+PrintGCDetails # 打印详细 GC 信息 -XX:+HeapDumpOnOutOfMemoryError # 内存溢出时自动生成堆转储 -XX:HeapDumpPath=./temp/dump.hprof ``` #### 2. 临时缓解措施 - **增加堆内存**(治标): ```bash -Xmx4g -Xms4g # 将最大/初始堆内存设为 4GB ``` - **禁用 GC 开销限制**(仅限紧急情况): ```bash -XX:-UseGCOverheadLimit # 关闭限制(可能掩盖根本问题)[^1] ``` #### 3. 根本性优化 - **代码优化**: - 避免创建短生命周期的大对象(如循环内 `new ArrayList()`) - 使用 `StringBuilder` 替代字符串拼接 - 及时关闭资源(数据库连接、文件流等) - **内存泄漏修复**: - 使用工具(如 **Eclipse MAT** 或 **VisualVM**)分析 `dump.hprof`,定位未释放的对象引用 #### 4. 调整垃圾回收策略 - **更换高效 GC 算法**(如 G1 回收器): ```bash -XX:+UseG1GC # 启用 G1 收集器 -XX:MaxGCPauseMillis=200 # 设置最大 GC 停顿时间 ``` #### 5. 长期监控 - **持续分析 GC 日志**:通过工具(如 **GCViewer**)观察 Full GC 频率内存回收效率 - **升级 JVM 版本**:新版 JDK(如 JDK 17+)的 ZGC/Shenandoah 收集器可显著降低 GC 开销 --- ### 关键操作示例 ```java // 错误示例:内存泄漏(未清除静态Map) public class Cache { private static Map<String, Object> dataMap = new HashMap<>(); public static void addData(String key, Object value) { dataMap.put(key, value); // 长期持有对象引用 } } // 修正方案:使用 WeakHashMap 或定期清理 private static Map<String, Object> dataMap = new WeakHashMap<>(); ``` --- 相关问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值