昆仑弟子_面霸
08-14·后端开发·10年+
面试吊打面试官
面试官:你先说说,ThreadLocal为什么会内存泄漏?我:ThreadLocalMap的Entry是弱引用key,但value是强引用。ThreadLocal对象本身如果只被Entry的弱引用持有,下次GC就会被回收,key变成null。但value还被Entry强引用着,而Entry又被ThreadLocalMap引用,ThreadLocalMap又是Thread的成员变量。只要线程不死,这条引用链就一直在,value就回收不掉面试官:那在线程池的场景下,你觉得问题出在哪?我:线程池的核心线程是复用的,不会销毁。线程不销毁,ThreadLocalMap就一直存在。如果业务代码用了ThreadLocal但没remove,value就一直挂在那个线程上。随着任务不断提交,不同任务的value越积越多,最后就是堆内存撑爆。面试官:你实际项目里怎么避免这个坑?我:ThreadLocal用完必须remove,放在finally块里。框架层面做统一拦截,比如Spring的RequestContextHolder就是在请求结束时清理。线上监控ThreadLocal的使用,通过反射定期扫描ThreadLocalMap里的staleentry数量。面试官:你说的反射扫描具体怎么做?我:通过反射拿到Thread对象的threadLocals字段,也就是ThreadLocalMap。再反射拿table数组,遍历每个Entry,检查key是否为null。如果key为null但value不为null,就是泄漏的entry。可以把这些value的类型和大小记日志,方便定位是哪个业务代码漏了remove。面试官:remove不就行了吗,为什么要搞这么复杂?我:remove是开发规范,但规范会被破坏。几百号人协作的项目,总有人忘记。线上出了问题不能等代码改完再排查,得先发现、先定位。而且有些第三方库内部用ThreadLocal也不会remove,你改不了它的代码,只能靠监控发现,然后通过线程池隔离把影响范围控制住
发布于 广东
8
8
8
未登录
友善发言
评论
加载中
下载脉脉APP,成就职业梦想
违法不良信息&未成年人有害信息举报电话/客服电话:400 065 0808
违法不良信息&未成年人有害信息举报邮箱/客服邮箱:maimai@taou.com
清朗系列专项行动相关违规信息举报电话:400 065 0808,举报邮箱:maimai@taou.com
个人/企业等被诽谤侮辱、人身权或知识产权等被侵犯、网络谣言的举报地址:maimai.cn/tousu | 涉企虚假不实信息举报投诉专区
京ICP备12005786号-1copyright©maimai.cn