美文网首页Java后端开发
项目卡顿问题追踪

项目卡顿问题追踪

作者: Zxlin2015 | 来源:发表于2017-11-02 17:26 被阅读18次

    1.物联网项目开发已经基本完成,最近在部署项目到实际环境,本地小数据测试,没啥问题,一上真实环境130个工厂,将近2000个传感器(只是一部分,还没全上),各种问题都来了,不多说,直接看项目卡顿的问题。

    2.最开始部署项目时一直卡顿,但是没找出什么问题导致,以为是开启的线程多(一个工厂对应一个线程)占用的内存会多一些,便在myeclipse调试环境配置了tomcat内存分配参数-Xms1024m -Xmx1024m和jdk内存分配参数-Xms1024m -Xmx1024m -Xmn512m  -XX:MaxPermSize=384m  - XX:ReservedCodeCacheSize=64m

    内存泄露导致连接数据库失败

    3.然而在项目运行一段时间之后变报出以下错误,让我以为只是数据连接池的可用连接数量不够,便去修改<property name="maxActive" value="20">为<property name="maxActive" value="2000"/>

    4.但之后项目仍旧一直很卡,便找来jconsole小工具查看项目启动时内存的变化,看一下是什么时候开始内存占用多,在项目完全启动之后发现内存占用一下子全上去了,先定位到工厂线程启动时执行的代码,主要为轮询传感器的数据,没发现有非常占用内存的循环

    jconsole内存使用情况

    5.在工厂线程启动完之后,缓存数据时出现了新的错误,如下截图,这次的错误提示直接提醒了我,原来是我在缓存项目数据时调用的日期格式化工具类没写好,经检测发现我缓存数据时需要多次调用格式化工具,每调用一次格式化方法都new了一个格式化对象值,而且没有释放引用导致内存占用特别多。

    频繁new SimpleDateFormat导致内存泄露 不好的代码

    6.经过修改之后的格式化工具代码如下,再次启动时发现在缓存数据处的循环内部调用System.gc()才是导致系统非常卡的真正原因,应将其移出到循环之外(时间消耗差不多7秒),再次启动项目相对没那么卡了。

    修改后的代码

    7.为了使项目能在启动之后快速响应前端的请求,在项目启动时我将工厂详情需要的数据直接缓存到redis,由于我使用FASTJson拼装缓存的数据存到redis需要转成string,所以通过调用toJSONString(),但当项目启动到数据多的工厂时还是会出现内存泄漏的错误,至此发现不止日期格式化工具代码会导致内存泄露,对于toJSONString在源码中已经有对循环引用做了处理,但数据太多仍旧会导致转换出现内存问题,由于我使用的是redis的string类型,因此只需要通过将json+""转成字符串存储,当需要时取出再还原即可,效率相对toJSONString()高,而且不会出现内存问题。

    8.最后对于内存占用多的问题,减少缓存到内存中数据量(原本缓存所有传感器历史数据,并且没有定期清除,随着项目运行,数据量会越来越多,迟早会把内存占用完),现在改成使用Map中套LinkBlockQueue以工程id作为key来缓存一周的数据,并且超过一周的数据就从队列中移除,redis则缓存最近一年的数据,超过时间就清理。

    9.小结,开发过程中尽量减少不必要的new对象操作,new完的对象应尽量手动置为null或者调用System.gc提醒jvm来回收不必要的对象(特别是在嵌套循环中要注意),也可使用weakReference等来控制内存使用,最后在写工具类时不要为了图省事直接随便new对象,否则会容易跟我一样踩坑的。

    10.最新优化后项目运行情况,

    项目运行情况

    相关文章

      网友评论

        本文标题:项目卡顿问题追踪

        本文链接:https://www.haomeiwen.com/subject/hwfgpxtx.html