文章简述:
PageHelper内存泄露的原因:
(PageHelper底层是基于MyBatis 的拦截器实现,分页参数存储在ThreadLocal中,会自动在SQL语句后面追加分页参数)
如果我们在写pagehelp的时候不规范,比如startPage后未紧跟sql语句,导致了代码异常,从而使得线程内的分页参数未被消费掉(因为未进行sql拼接,所以pagehelp未能调用endpage或者clrean清空线程内存储的分页参数),从而导致,当这条线程执行其他任务时(比如其他方法或者controller的入口),即使该方法不涉及分页,但是因为线程内存在未被消费掉的分页参数,所以在进行SQL操作时,被错误的追加到SQL上面,从而造成生产事故。
解决方法:
1:编程时,注意startpage后紧跟sql,或者手动释放掉
2:出现问题,找到源头优化代码。或者基于aop加一个方法对所有返回的线程进行分页参数清理
如果新的 SQL 查询未使用 PageHelper:
如果新的方法中没有调用 startPage,而是直接执行了普通的 SQL 查询,那么之前遗留的分页参数可能会错误地应用到这些查询上,导致 SQL 拼接错误。
这种情况下,分页参数不会被清理,因为没有触发 PageHelper 的清理逻辑。
原理:MyBatis 拦截器
PageHelper 是基于 MyBatis 的拦截器实现的。它的拦截器会在执行 SQL 查询时动态修改 SQL 语句(添加分页逻辑),并在查询完成后清理 ThreadLocal 中的分页参数。
编写注意
1:startPage后紧跟SQL语句
原因:确保分页参数被消费掉,并正确执行分页参数清理操作
存在内存泄露的点
1:startPage后跟不相关的代码(可能爆异常导致未被正确消费及清理掉)
未正确消费掉:本来要给查询用户的sql分页,但是这个sql上面有个查询工单,给查询工单的分页了
未正确清理:如果startPage -> SQL 中间的代码爆了异常,则无法自动清理线程的分页数据,导致内存泄漏
解决:
1:finally强制clearPage 或 endPage 。
endPage :分页结束后回收
clearPage:强制立即回收,不管当前是否在执行
几种情况(未finall或手动回收)
1:分页参数被消费前,抛出异常(内存泄漏)
2:执行sql时抛出异常 (无内存泄漏)
2:分页参数被消费后,抛出异常(无内存泄漏)
https://zhuanlan.zhihu.com/p/681321312
【出现后】万能解决方法
1:排查内存泄漏点,优化代码,源头解决
2:排查不到内存泄漏点
2.1:AOP对所有可能存在的点强制clearPage