Tomcat:Caused by: java.lang.OutOfMemoryError: PermGen space

本文介绍了解决Tomcat中出现的PermGenSpace内存溢出错误的方法。PermGenSpace是JVM用于存储Class和Meta信息的永久区域,当第三方jar文件过多导致内存不足时,会出现该错误。可以通过增大-Xmx参数分配更多的内存或将重复的jar文件放置在shared/lib目录下以减少内存占用。
转自:http://hi.baidu.com/zoomx/blog/item/77d93ca819f0a0b0cb130c8d.html

项目中遇到了系统停止响应的问题,查看日志发现

Tomcat报告Caused by: java.lang.OutOfMemoryError: PermGen space异常,开始以为是程序内存泄漏导致的内存溢出,网上查了一下,原来是另有原因,不过确实是内存溢出

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,
这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen
space中,
它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运
行期对
PermGen space进行清理,所以如果你的应用中有很多CLASS的话,就很可能出现PermGen
space错误,
这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大
量的第三方jar, 其大小
超过了jvm默认的大小(4M)那么就会产生此错误信息了。
解决方法: 手动设置MaxPermSize大小

设置参数:-Xms256m -Xmx512m -XX:MaxNewSize=256m -XX:MaxPermSize=256m

Tomcat中,修改TOMCAT_HOME/bin/catalina.sh(linux系统下start.sh会调用它来启动tomcat,windows下调用catalina.bat,修改类似)

在文件头部注释后加入
JAVA_OPTS='-Xms256m -Xmx512m -XX:MaxNewSize=256m -XX:MaxPermSize=256m'


如果tomcat运行多个系统,将相同的第三方jar文件移置到tomcat/shared/lib目录下,这样可以达到减少
jar 文档重复占用内存的目的。


------------------

看得出来,是在Tomcat等在加载ApplicationContext过程中,由于初始的Bean过多而发生的OOM。解决方法就是给Tomcat启动加大启动内存。

[1] 如果是在Eclipse中的Tomcat启动的,在启动配置中设置一个参数
-Xmx512m 当然视你自己情况配置一个大小。

在我的Eclipse的Tomcat的Run Configuration的VM arguments的内容如下:
引用-Dcatalina.base="D:\WORKSPACE\SDK-3.4\RAP\.metadata\.plugins\org.eclipse.wst.server.core\tmp0" -Dcatalina.home="D:\JAVA\apache-tomcat-5.5.20" -Dwtp.deploy="D:\WORKSPACE\SDK-3.4\RAP\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps" -Djava.endorsed.dirs="D:\JAVA\apache-tomcat-5.5.20\common\endorsed" -Xmx512m

[2] 如果直接使用Tomcat启动的,
找到tomcat\bin\catalina.bat文件,同样也是加这个启动参数。
下面是我的Tomcat的catalina.bat文件配置效果:
引用set JAVA_OPTS=%JAVA_OPTS% -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties" -Xmx512m
<think>首先,用户查询是:“我想查找Web服务器无法启动且嵌套异常为java.lang.StackOverflowError的解决办法”。所以,我需要提供解决这个特定异常的方法。 用户提供了三个引用: - 引用[1]:讨论PermGen空间错误(java.lang.OutOfMemoryError: PermGen space),这发生在永久代内存耗尽时。 - 引用[2]:讨论异常处理的最佳实践,建议捕获特定异常而不是通用的Exception。 - 引用[3]:展示一个简单的ArrayIndexOutOfBoundsException处理示例。 这些引用似乎与用户的当前查询不直接相关。用户的查询是关于StackOverflowError的,而引用[1]是关于OutOfMemoryError的。StackOverflowError和OutOfMemoryError都是错误类(Error的子类),但原因不同:StackOverflowError是由无限递归或方法调用栈耗尽引起的,而OutOfMemoryError是由堆内存不足引起的。 我的系统指令要求: - 使用$...$格式用于行内数学表达式(尽管这里可能不需要数学)。 - 使用$$...$$格式用于独立公式。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 - 参考用户上一次的问题和我的回答:用户上一次的问题是关于StackOverflowError的解决办法,我需要基于当前的引用信息。 用户提供的引用不是直接相关的: - [1]:PermGen错误(常见于旧Java版本),不是StackOverflowError。 - [2]:通用异常处理建议。 - [3]:数组索引错误处理。 所以,我应该基于我的知识提供正确的解决办法,同时参考这些信息来增强回答。 关键点: - java.lang.StackOverflowError通常表示无限递归或深度嵌套的方法调用导致调用栈溢出。 - 在Web服务器启动时发生,可能是由于依赖注入循环、Spring上下文问题、递归配置等。 解决办法步骤: 1. 识别递归点:检查代码中是否有无限递归或深度递归的方法。 2. 查看堆栈跟踪:分析错误日志,找出是哪个方法导致栈溢出。 3. 增加堆栈大小:使用JVM参数增加线程栈大小,如-Xss。 4. 优化代码:移除不必要的递归,使用迭代替代。 5. 检查框架配置:如果是Spring或其他框架,检查是否有循环依赖。 6. 使用调试工具:分析调用栈。 由于引用[1]提到了JVM参数(-XX:MaxPermSize),我可以类比建议调整栈大小参数。引用[2]和[3]是关于异常处理的,StackOverflowError是错误,不是异常,所以捕获它可能不是好主意,因为它表示严重问题。 在回答中: - 使用中文。 - 结构清晰:逐步解释。 - 添加引用标识:参考提供的引用适当引用它们。 - 生成相关问题。 可能的解决方案: 1. 分析错误日志:查找嵌套异常根源。 2. 增加线程栈大小:使用JVM参数如-Xss512k或-Xss1m。 3. 代码审查:检查递归方法或循环依赖。 4. 使用工具:如Java VisualVM分析堆栈。 参考引用: - 引用[1]讨论了JVM参数,所以我可以说类似地调整栈大小参数。 - 引用[2]建议捕获特定异常,但StackOverflowError不应该被捕获;它应该被修复。 - 引用[3]是一个简单例子,不直接相关。 生成相关问题: - 基于主题,如如何预防StackOverflowError、JVM参数调整等。 回答结构: - 介绍问题。 - 解释原因。 - 提供解决办法。 - 添加引用标识适当。 - 结束相关问题。 </think>### Web服务器无法启动且嵌套异常为java.lang.StackOverflowError的解决办法 java.lang.StackOverflowError错误通常在Web服务器启动时发生,表示调用栈溢出。这通常是由于无限递归、深度嵌套的方法调用或框架配置问题(如Spring循环依赖)导致的。错误本身是JVM错误(Error的子类),而非普通异常,因此捕获它并不是根本解决方案(正如引用[2]所指出的,捕获通用异常Exception可能掩盖问题,但对于StackOverflowError,更应直接修复代码或配置)。下面我将基于常见实践,结构化地提供解决办法。请确保在操作前备份代码和环境。 #### 原因分析 StackOverflowError发生在方法调用栈耗尽时,常见原因包括: - **无限递归**:方法无终止条件地调用自身。 - **深度依赖注入**:如Spring框架中的循环引用(A依赖B,B又依赖A)。 - **大型数据结构处理**:递归算法深度过高。 - **JVM配置不当**:线程栈大小不足(默认值可能过小)。 引用[1]中提到的PermGen错误与此类似,都是内存相关问题,但StackOverflowError针对调用栈而非堆内存。错误日志中的嵌套异常线索(如`Caused by: java.lang.StackOverflowError`)是关键切入点。 #### 逐步解决方法 1. **分析错误日志,定位根源** 检查服务器启动日志,找出异常堆栈跟踪(stack trace)。例如: ```plaintext Caused by: java.lang.StackOverflowError at com.example.Service.methodA(Service.java:10) at com.example.Service.methodB(Service.java:15) ``` 聚焦于频繁重复的方法调用点(如上例中的`methodA`和`methodB`)。这可以帮助识别递归循环或依赖问题。工具如JVisualVM或Eclipse MAT可以辅助分析堆栈。 2. **增加JVM线程栈大小** 类似引用[1]中调整`-XX:MaxPermSize`,您可以通过JVM参数增加栈大小。在服务器启动脚本(如Tomcat的catalina.sh或Spring Boot的application.properties)中添加: ```bash -Xss512k # 或 -Xss1m,512KB或1MB,根据需求调整 ``` 默认栈大小通常为256KB-1MB(取决于JVM),增加后可缓解浅层溢出问题。但这不是长久方案,仅作为临时测试。 3. **检查和优化代码** - **消除无限递归**:确保递归方法有终止条件。例如,替换递归为迭代: ```java // 错误:无限递归风险 public void recursiveMethod() { recursiveMethod(); // 无退出条件 } // 修复:使用循环迭代 public void iterativeMethod() { while (condition) { // 逻辑 } } ``` - **解决框架循环依赖**:在Spring等框架中,使用`@Lazy`注解或重构设计: ```java @Service public class ServiceA { @Lazy @Autowired private ServiceB serviceB; // 延迟注入打破循环 } ``` 引用[3]中的示例强调了特定异常处理,但StackOverflowError是错误类型,不应捕获处理;重点应是预防(如避免数组越界类似的无界调用)[^3]。 4. **代码审查和测试** - 使用IDE调试模式设置断点,模拟启动过程。 - 单元测试递归方法:添加边界测试用例。 - 工具扫描:如SonarQube检测递归风险。 5. **若问题持续,深入诊断** - **减小栈大小测试**:临时设置`-Xss128k`强制复现错误,确认优化点。 - **升级环境**:确保JDK版本兼容(旧版JVM栈管理较弱)。 - **监控工具**:使用`jstack <pid>`导出线程堆栈分析。 #### 预防建议 - **避免深度递归**:在算法设计中,限制递归深度(如设置最大深度计数器)。 - **框架最佳实践**:在Spring中禁用不必要的自动扫描(使用`@ComponentScan` excludeFilters)。 - **日志监控**:服务器启动时启用详细日志(如Spring Boot的`logging.level.root=DEBUG`)。 StackOverflowError的根本解决需结合代码优化和JVM调优。引用[2]强调捕获异常时要具体化,但针对此错误,优先修复而非捕获[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值