工作中,即席查询,涉及到对sql语句进行切割。解析sql中的注释信息。使用正则表达式匹配分组,进行处理。
早上,数仓人员提供一个很长的sql(sql很长,此处省略)。
发现,执行后怎么也不出来结果。看了系统日志,也没发现报错信息,很奇怪。
线上环境无Exception日志输出。于是,进行本地调试,现象重现了。
代码
123456789101112131415
/** * 去除sql注释 * @param sql * @return 返回去除注释后的sql */public static String removeSqlRemark(String sql) { logger.info("removeSqlRemark sql={}",sql); String realSql = sql; Pattern p = Pattern.compile("(?ms)('(?:''|[^'])*')|(\"(?:\"\"|[^\"])*\")|--.*?$|/\\*.*?\\*/"); realSql = p.matcher(realSql).replaceAll("$1$2"); logger.info("before format realSql={}",realSql); realSql = SqlUtil.formatSql(realSql); logger.info("after format realSql={}",realSql); return realSql;}
发现出现如下错误:
123456
Exception in thread "main" java.lang.StackOverflowError at java.util.regex.Pattern$Loop.match(Pattern.java:4785) at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717) at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568) at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777) ......
看到这里,就是堆栈溢出。看了报错的代码,是正则表达式解析问题。
然后,搜一下关键字“正则表达式 java.lang.StackOverflowError”。
搜出很多匹配的答案,其中有一篇描述的很透彻。
Java 正则表达式 StackOverflowError问题及其优化 。
-Xss 每个线程的Stack大小 Stack的大小限制着线程的数量.如果Stack过大就好导致内存溢漏.-Xss参数决定Stack大小,例如-Xss1024K.如果Stack太小,也会导致Stack溢漏。
使用idea 验证,修改main 的run jvm参数。
配置-Xss256k,-Xss512k,-Xss1m。然后,运行无上述问题。
java 正则表达式会出现递归调用( 递归方法也要注意 )。这就会出现栈溢出的风险。所以,在使用正则表达式的同时,注意堆栈溢出问题。 不可用 Exception 捕获,因为 Error 直接继承自 Throwable 而非 Exception,所以即使你要捕获也应当捕获 Error。