专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

慧销平台ThreadPoolExecutor内存泄漏分析

  作者:京东零售冯晓涛问题背景
  京东生旅平台慧销系统,作为平台系统对接了多条业务线,主要进行各个业务线广告,召回等活动相关内容与能力管理。
  最近根据告警发现内存持续升高,每隔23天会收到内存超过阈值告警,猜测可能存在内存泄漏的情况,然后进行排查。根据24小时时间段内存监控可以发现,容器的内存在持续上升:
  问题排查
  初步估计内存泄漏,查看24小时时间段jvm内存监控,排查jvm内存回收情况:
  YoungGC和FullGC情况:
  通过jvm内存分析和YoungGC与FullGC执行情况,可以判断可能原因如下:
  1、存在YoungGC但是没有出现FullGC,可能是对象进入老年代但是没有到达FullGC阈值,所以没有触发FullGC,对象一直存在老年代无法回收
  2、存在内存泄漏,虽然执行了YoungGC,但是这部分内存无法被回收
  通过线程数监控,观察当前线程情况,发现当前线程数7427个,并且还在不断上升,基本判断存在内存泄漏,并且和线程池的不当使用有关:
  通过JStack,获取线程堆栈文件并进行分析,排查为什么会有这么多线程:
  发现通过线程池创建的线程数达7000:
  代码分析
  分析代码中ThreadPoolExecutor的使用场景,发现在一个worker公共类中定义了一个线程池,worker执行时会使用线程池进行异步执行。publicclassBackgroundWorker{privatestaticThreadPoolExecutorthreadPoolExecutor;static{init(15);}publicstaticvoidinit(){init(15);}publicstaticvoidinit(intpoolSize){threadPoolExecutornewThreadPoolExecutor(3,poolSize,1000,TimeUnit。MINUTES,newLinkedBlockingDeque(1000),newThreadPoolExecutor。CallerRunsPolicy());}publicstaticvoidshutdown(){if(threadPoolExecutor!null!threadPoolExecutor。isShutdown()){threadPoolExecutor。shutdownNow();}}publicstaticvoidsubmit(finalRunnabletask){if(tasknull){return;}threadPoolExecutor。execute((){try{task。run();}catch(Exceptione){e。printStackTrace();}});}}
  广告缓存刷新worker使用线程池的代码:publicclassAdActivitySyncJob{Scheduled(cron005?)publicvoidexecute(){log。info(AdActivitySyncJobstart);ListDicDTOlocationListlocationService。selectLocation();if(CollectionUtils。isEmpty(locationList)){return;}中间省略部分无关代码BackgroundWorker。init(40);locationCodes。forEach(locationCode{showChannelMap。forEach((key,value){BackgroundWorker。submit(newRunnable(){Overridepublicvoidrun(){log。info(AdActivitySyncJob,locationCode:{},showChannel:{},locationCode,value);ResultresultnotLoginAdActivityOuterService。getAdActivityByLocationInner(locationCode,ImmutableMap。of(showChannel,value));LocalCache。ADACTIVITYCACHE。put(locationCode。concat()。concat(value),result);}});});});log。info(AdActivitySyncJobend);}PostConstructpublicvoidinit(){execute();}}
  原因分析:猜测是worker每次执行,都会执行init方法,创建新的线程池,但是局部创建的线程池并没有被关闭,导致内存中的线程池越来越多,ThreadPoolExecutor在使用完成后,如果不手动关闭,无法被GC回收。分析验证
  验证局部线程池ThreadPoolExecutor创建后,如果不手动关闭,是否会被GC回收:publicclassTest{privatestaticThreadPoolExecutorthreadPoolExecutor;publicstaticvoidmain(String〔〕args){for(inti1;i100;i){每次均初始化线程池threadPoolExecutornewThreadPoolExecutor(3,15,1000,TimeUnit。MINUTES,newLinkedBlockingDeque(1000),newThreadPoolExecutor。CallerRunsPolicy());使用线程池执行任务for(intj0;j10;j){submit(newRunnable(){Overridepublicvoidrun(){}});}}获取当前所有线程ThreadGroupgroupThread。currentThread()。getThreadGroup();ThreadGrouptopGroupgroup;遍历线程组树,获取根线程组while(group!null){topGroupgroup;groupgroup。getParent();}intslackSizetopGroup。activeCount()2;Thread〔〕slackThreadsnewThread〔slackSize〕;获取根线程组下的所有线程,返回的actualSize便是最终的线程数intactualSizetopGroup。enumerate(slackThreads);Thread〔〕atualThreadsnewThread〔actualSize〕;System。arraycopy(slackThreads,0,atualThreads,0,actualSize);System。out。println(ThreadssizeisatualThreads。length);for(Threadthread:atualThreads){System。out。println(Threadname:thread。getName());}}publicstaticvoidsubmit(finalRunnabletask){if(tasknull){return;}threadPoolExecutor。execute((){try{task。run();}catch(Exceptione){e。printStackTrace();}});}}
  输出:
  Threadssizeis302
  Threadname:ReferenceHandler
  Threadname:Finalizer
  Threadname:SignalDispatcher
  Threadname:main
  Threadname:MonitorCtrlBreak
  Threadname:pool1thread1
  Threadname:pool1thread2
  Threadname:pool1thread3
  Threadname:pool2thread1
  Threadname:pool2thread2
  Threadname:pool2thread3
  Threadname:pool3thread1
  Threadname:pool3thread2
  Threadname:pool3thread3
  Threadname:pool4thread1
  Threadname:pool4thread2
  Threadname:pool4thread3
  Threadname:pool5thread1
  Threadname:pool5thread2
  Threadname:pool5thread3
  Threadname:pool6thread1
  Threadname:pool6thread2
  Threadname:pool6thread3
  执行结果分析,线程数量302个,局部线程池创建的核心线程没有被回收。
  修改初始化线程池部分:初始化一次线程池threadPoolExecutornewThreadPoolExecutor(3,15,1000,TimeUnit。MINUTES,newLinkedBlockingDeque(1000),newThreadPoolExecutor。CallerRunsPolicy());for(inti1;i100;i){使用线程池执行任务for(intj0;j10;j){submit(newRunnable(){Overridepublicvoidrun(){}});}}
  输出:
  Threadssizeis8
  Threadname:ReferenceHandler
  Threadname:Finalizer
  Threadname:SignalDispatcher
  Threadname:main
  Threadname:MonitorCtrlBreak
  Threadname:pool1thread1
  Threadname:pool1thread2
  Threadname:pool1thread3解决方案
  1、只初始化一次,每次执行worker复用线程池
  2、每次执行完成后,关闭线程池
  BackgroundWorker的定位是后台执行worker均进行线程池的复用,所以采用方案1,每次在static静态代码块中初始化,使用时无需重新初始化。
  解决后监控:
  jvm内存监控,内存不再持续上升:
  线程池恢复正常且平稳:
  Jstack文件,观察线程池数量恢复正常:
  Dump文件分析线程池对象数量:
  拓展1、如何关闭线程池
  线程池提供了两个关闭方法,shutdownNow和shutdown方法。
  shutdownNow方法的解释是:线程池拒接收新提交的任务,同时立马关闭线程池,线程池里的任务不再执行。
  shutdown方法的解释是:线程池拒接收新提交的任务,同时等待线程池里的任务执行完毕后关闭线程池。2、为什么threadPoolExecutor不会被GC回收threadPoolExecutornewThreadPoolExecutor(3,15,1000,TimeUnit。MINUTES,newLinkedBlockingDeque(1000),newThreadPoolExecutor。CallerRunsPolicy());
  局部使用后未手动关闭的线程池对象,会被GC回收吗?获取线上jump文件进行分析:
  发现线程池对象没有被回收,为什么不会被回收?查看ThreadPoolExecutor。execute()方法:
  如果当前线程数小于核心线程数,就会进入addWorker方法创建线程:
  分析runWorker方法,如果存在任务则执行,否则调用getTask()获取任务:
  发现workQueue。take()会一直阻塞,等待队列中的任务,因为Thread线程一直没有结束,存在引用关系:ThreadPoolExecutorWorkerThread,因为存在GCROOT的引用,所以无法被回收。

华为mate10升级了鴻蒙系统后还可以用4年吗?感谢您的阅读!我自己使用的是华为mate20Pro,并且这款手机也升级了鸿蒙系统。我和大家可以聊聊这款手机的体验,然后再和大家一起去说一说,华为mate10,升级鸿蒙系统之后,能不手机在保修期内,我想问一下,手机不是故意的掉到水里,店主说是不保修?这合理吗?不保修非常合理。有时候,我们也不能让无知成为了自己理直气壮的理由,要想知道手机是不是能够保修,我们可以拿出国家三包规定好好的读一下。现在最新的手机三包规定是啥?从手机购买日期计算1银耳糕怎么做?银耳糕怎么做,银耳糕的做法有很多种,银耳可以搭配各种食材来做银耳糕,像红枣山药鸡蛋雪梨等,制作出来的银耳糕,营养丰富又好吃,自己在家做,制作简单又好吃,老少皆宜。银耳营养丰富,也是如果琼州隧道修成,海南的发展会怎样?关于琼州海峡建隧道的想法,受到越来越多人的关注,也有很多专家学者提出了集体的规划方案。作为一个土生土长的海南人,我也很期待琼州海峡隧道的建设。现在海南人出岛最便捷的方式就是乘坐飞机山西六日游该怎么游玩?有句话叫地下文物看陕西,地上文物看山西!山西文化底蕴深厚,省内留存着非常多有上千年历史的古庙石窟老城墙等一系列的历史遗迹!所以山西游首推从人文历史方面去着重感受!题主要山西6日游的我小孩校招进了西安中兴通讯,请在西安的亲们,这个单位怎么样?非常好!我就在!中国第一家上市通信公司。通信行业,目前华为第一,中兴第二,中兴全球排名第四,是一家国际化的大公司。我有一个同事,儿子毕业后去了西安的中兴通讯,几年前辞职了,原因是没吃什么菜能养肝?大蒜,就是象鼻子插葱装的那个蒜,开个小玩笑。正所谓四季不离蒜,不用去医院大蒜具有非常好的保健作用,尤其是对肝脏。大家都知道肝脏是人体重要的排毒器官,大蒜能够诱导肝细胞脱毒酶的活性,疱疹为什么反复发作呢?疱疹指疱疹病毒科病毒所致疾病,表现为局限性隆起性内含液体的腔隙性皮损,目前已知在疱疹病毒科中有八种病毒(单纯疱疹病毒12型,水痘带状疱疹病毒,人巨细胞病毒,EB病毒和人类疱疹病毒6三一重工,11。9走势分析,有多少人还在持有?有多少人等待抄底?难哦。三一重工一直以来的下跌,是对价值投资者最大的打击,因为公司大,业务广,业绩好,吸引了115万股东,股价大跌,而股东人数在一个季度里还涨了17。20,现在把所有抄底的都套得牢牢一线教师如何创造高级职称的业绩条件?提到职称,就是一线老师心头的痛,机会都是留给有准备的人,坐等花开是不可能评上职称的,一线教师如何才能创造条件评上高级职称呢?我认为应从以下几方面入手。一学校要有高级职称指标。这是评一个母亲怎么做到对自己的子女不闻不问的?我婆婆嫌弃公公穷,而抛夫弃子再改嫁有钱人。离婚后,20几年对她儿子(即我的丈夫)不闻不问,老了却想让我丈夫给她养老,还各种嫌弃我丈夫。据丈夫说,在他3岁时,他父母就离婚了,他由他父
耐心能够创造奇迹耐心是水滴石穿,是绳锯木断耐心是岩缝中生长的小草,是沙漠中蜿蜒的细流耐心是守得云开见月明,是漫天风雨终得晴耐心是一棵藤蔓爬上高楼顶,是一只蜘蛛结成空中网,耐心能够创造奇迹,耐心也总强大自己才是根本莫言说你和任何人的关系,其实并不取决于你对别人有多好,而是取决于你的强弱,手上筹码的多少。人们普遍对强者比较宽容,而即使弱者没做错什么,也会被苛待。就算你一味忍气吞声,往往也会被看乱想这篇的内容是我平时存的草稿,因为这几天很忙没时间仔细推敲就都混合着发出去,略微看了下,还好没什么违和感我愿意因为一人而离开,远涉沧浪的海,不会不舍,因为已经学会清心,清除心中原本属有一种爱,叫在心里,每天想你一万遍情感点评大赏世间,有相聚,就会有别离,人间,有爱情,就会有相思,有一种爱,叫在心里,每天想你一万遍,不管岁月如何变迁,你永远都是我心里的温暖,我从不后悔爱上你,一场奔赴,是我一生的关晓彤的10幅美照,每幅都为珍藏款1。颠倒黑夜白昼,沉沦灰色世界。2。我感觉累极了,却又不可声张,不可心灰,不可退,我并不愿与你说话,怕张了口,就流泪。3。我拿灰色头像跟你赌赌你在不在乎我?当我没上线的时候你会不会过年调韭菜馅饺子,学会2加2不放,韭菜不烧心不出水,真香马上要过春节了,陆陆续续的在家准备年货,买了砂糖橘东北小花生开心果瓜子各种糖果,还预备了腊鱼腊肉炸藕夹炸肉丸炸鱼块,卤制了一些卤菜,有卤牛肉卤鸡爪卤猪耳朵卤藕片等。主食方面,前几天明天除夕,老人讲5菜不上桌,福气不进门,5菜到底指的啥头条创作挑战赛爆竹声中一岁除,春风送暖入屠苏。千门万户曈曈日,总把新桃换旧符。除夕是我国最重要的传统节日,既承载了辞旧迎新的美好愿望,又寄托了展望未来的美好篇章。就是这样一个个传统年底了,问自己!(问到心酸)时针走一圈,一天过完四季轮一圈,一年过完。眨眼之间旧岁去,百味陈杂自己知!过去的一年里,谁对你感同身受?谁把你力挺到底?无人问津的时候居多,有人心疼的时候寥寥。苦累不易的人生,我们CBA最新积分榜浙江斩北京2分领跑广东胜辽宁还落后1分吉林第10北京时间1月18日,CBA联赛第28轮第二比赛日结束了5场比赛,浙江9488战胜北京,积52分继续领跑,北京积45分排第6。广东10899战胜辽宁,积49分排名第3,辽宁积50分排卡戴珊前任又恋爱,十指紧扣曝光!颜值身材不如金姐,口味变了当地时间1月20日,金卡戴珊的前男友皮特戴维斯(PeteDavidson)新恋情正式曝光,他与女演员ChaseSui十指紧扣,出现在环球影城,之前就传出两人交往的消息,但一直没有确对女孩子不要以礼相待永远一本正经,那你们永远只能是朋友!纵有疾风起征文1对女孩子不要以礼相待。永远一本正经,那你们永远只能是朋友。她喜欢你的话,你甚至强吻她,她都不会真的生气,只是会觉得有点快。2当一个人跟你说只想搞钱的时候,基本可以确
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网