首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > Ruby Rails >

关于Java正则引起的StackOverFlowError有关问题以及解决方案

2012-11-18 
关于Java正则引起的StackOverFlowError问题以及解决方案java 正则异常 java.lang.StackOverflowError:在使

关于Java正则引起的StackOverFlowError问题以及解决方案

java 正则异常 java.lang.StackOverflowError:
 
 在使用正则表达式的时候,底层是通过迭代方式执行的,每一层的迭代都会在栈线程的大小中占一定内存,如果迭代的层次很多,就会报出stackOverFlowError异常。所以在使用正则的时候其实是有利有弊的。我们使用的weblogic服务器,修改了配置-Xss的大小为512K后,测试几次没有报错。现在修改成了1M,再观察一段时间。修改-Xss只是治标不治本的解决方法,要从根源上解决还需要优化正则。

 

以下是从网络上摘抄的:


根本原因是这样的,对于每一个线程,都有一个java栈 ,当有一个方法被调用的时候,会产生一些跟这个方法相关的信息,如方法名,参数,中间变量等等,这些叫做栈帧 ,当一个方法执行完毕  这个栈帧才会从栈顶pop掉  你递归的话  会一直向栈里push栈帧  而这个java栈是有一定的长度或深度的,当栈满了,无法再进行push的时候 就出现你上面的异常了,解决办法的话 就不要用递归操作 改用for 而且平时也不建议用递归的,效率太低了 .
参考网址:http://bbs.csdn.net/topics/370099884

栈溢出了,JVM依然是采用栈式的虚拟机,这个和C和Pascal都是一样的。函数的调用过程都体现在堆栈和退栈上了。你调用构造函数的“层”太多了,以致于把栈区溢出了。
通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要1K的空间(这个大约相当于在一个C函数内声明了256个int类型的变量),那么栈区也不过是需要1MB的空间。通常栈的大小是1-2MB的。通常递归也不要递归的层次过多,很容易溢出.
参考网址:http://bbs.csdn.net/topics/380047221


对java.lang.StackOverflowError的分析:
原因:运行一个程序,JVM会开辟一块内存空间去储存程序进行时的某些信息,当程序运行时需要储存的信息超过了分配的空间,就会出现那样的问题.比如死循环,
解决:首先从程序代码优化方面着手,检查是否有死循环、递归等程序,如果有,修正、优化相关代码。
参考网址:http://blog.csdn.net/gaomatrix/article/details/6604579

 

有时regex包中的Pattern类会抛出StackOverflowError.这是已知的bug #5050507的表现,它自从Java 1.4就存在于java.util.regex包中。这个bug仍然存在,因为它是“won't fix”的状态。这个错误的出现是因为,Pattern类把一个正则表达式编译为一个用来寻找匹配的小程序。这个程序被递归调用,有时太多的递归就会导致该错误的出现。更多细节请参考bug描述。看起来大部分是在使用选择(alternation)的出现。
参考网址:http://edu.21cn.com/java/g_189_801829-1.htm

大致的描述一下问题,有一个正则匹配,本机环境可以正常匹配,在另一台服务器也可以正常匹配,但是只有一台 不行,我就怀疑是那台机器的环境问题,结果和我想的一样。
设置jvm参数
Xss 设置成默认即可
参考网址:http://blog.knowsky.com/190676.htm


Java程序中,每个线程都有自己的Stack Space。这个Stack Space不是来自Heap的分配。所以Stack Space的大小不会受到-Xmx和-Xms的影响,这2个JVM参数仅仅是影响Heap的大小。Stack Space用来做方法的递归调用时压入Stack Frame。所以当递归调用太深的时候,就有可能耗尽Stack Space,爆出StackOverflow的错误。Stack Space的大小随着OS,JVM以及环境变量的大小而发生变化。一般说来默认的大小是512K。在64位的系统中,这个Stack Space值会更大。一般说来,Stack Space为128K是够用的。这时你说需要做的就是观察。如果你的程序没有爆出StackOverflow的错误,可以使用-Xss来调整Stack Space的大小为128K。(eg:-Xss128K)
参考网址:http://thomaschen2011.iteye.com/blog/1214114


从异常信息来看,很明显,线程栈空间不足,一般来说,存在这种情况,是因为方法的嵌套调用层次太深,上层的方法栈一直得不到释放,导致栈空间不足。因为正则匹配的时候,嵌套层次太深,“()”太多太深。请记住一句老话:“ 您有一个问题,用正则表达式解决。那您就有两个问题了。” 
参考网址:http://www.iteye.com/topic/860654


sun公司发布的jdk,正则表达式bug网址:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507

 

关于:优化Java中的正则表达式
1、如果在程序中多次使用同一个正则表达式,一定要用Pattern.compile()编译,代替直接使用Pattern.matches()。如果一次次对同一个正则表达式使用Pattern.matches(),例如在循环中,没有编译的正则表达式消耗比较大。因为matches()方法每次都会预编译使用的表达式。另外,记住你可以通过调用reset()方法对不同的输入字符串重复使用Matcher对象。
2、留意选择(Beware of alternation)。类似“(X|Y|Z)”的正则表达式有降低速度的坏名声,所以要多留心。首先,考虑选择的顺序,那么要将比较常用的选择项放在前面,因此它们可以较快被匹配。另外,尝试提取共用模式;例如将“(abcd|abef)”替换为“ab(cd|ef)”。后者匹配速度较快,因为NFA会尝试匹配ab,如果没有找到就不再尝试任何选择项。(在当前情况下,只有两个选择项。如果有很多选择项,速度将会有显著的提升。)选择的确会降低程序的速度。在我的测试中,表达式“.*(abcd|efgh|ijkl).*”要比调用String.indexOf()三次——每次针对表达式中的一个选项——慢三倍。
3、获取每次使用引起小损失的分组。如果你实际并不需要获取一个分组内的文本,那么就使用非捕获分组。例如使用“(?:X)”代替“(X)”。
参考网址:http://blog.csdn.net/mydeman/article/details/1800636


(大概的意思就是,如果我们使用递归了,首先你得明白什么是递归,递归就是一个方法被调用N次。当方法被调用的时候,方法的参数,定义等信息会存在本次线程对应的java栈里。一个方法被调用N次,那就得往这个java栈里放N次。次数如果过多,那么java栈就会溢出。)

热点排行