<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          com.alibaba.fastjson存在內(nèi)存泄漏

          共 2447字,需瀏覽 5分鐘

           ·

          2022-01-01 05:23

          [背景]



          發(fā)現(xiàn)線上機器的元空間在增長,?發(fā)生了FGC.?

          由于拿不到線上機器的dump文件,?于是乎, 在預(yù)發(fā)環(huán)境,?執(zhí)行jmap命令, 得到dump文件.


          使用MemoryAnalyzer分析dump文件.



          如上圖, 在查看線程信息的時候,?發(fā)現(xiàn)Dubbo線程,?MQ線程,?xxl-job線程這些線程, 它們`持有`上百KB的內(nèi)存.?常規(guī)情況,?線程不會`持有`這么大的內(nèi)存.


          拿其中一個Dubbo線程, 查看下它內(nèi)部的屬性




          如上圖, 在線程的ThreadLocalMap中存在197.05KB的數(shù)據(jù)


          查看ThreadLocalMap中的信息



          如上圖, 在ThreadLocalMap的12號位置,?存儲了128.02KB的字符數(shù)組.?里面存儲的都是業(yè)務(wù)信息.?


          那么是由哪個ThreadLocal放到這個線程的ThreadLocalMap中的呢?


          往下看



          如上圖,在ThreadLocalMap中, ThreadLocal作為Key,?于是右擊圖中的ThreadLocal,?選擇`with incoming references`, 就可以查到到哪些引用了這個ThreadLocal.



          如上圖,?發(fā)現(xiàn)com.alibaba.fastjson.JSON引用了ThreadLocal.


          根據(jù)這個線索, 查看了下業(yè)務(wù)代碼.




          在業(yè)務(wù)代碼中,?使用了

          com.alibaba.fastjson.JSON#parseObject()

          跟進這個方法



          有一個allocateChars方法

          fastjson先從當(dāng)前線程中得到char[],如果沒有則創(chuàng)建一個char[], 并放入到線程的ThreadLocalMap中.

          這也是fastjson為了提高性能的一個手段. 但是它卻造成了內(nèi)存泄漏.?因為沒有任何地方調(diào)用了remove()方法.


          排查到這里后, 我去GitHub上查看了下, 原來在今年(2021年)5月份已經(jīng)有人在GitHub上提出了這個問題.



          地址:?https://github.com/alibaba/fastjson/issues/3751


          我也在下方貼出了我的案例(也就是本文所說的)




          但是, 似乎這個問題官方還沒有給出一個比較好的解決方案.?(master代碼和最新的1.2.79版本均沒有看到解決它的`身影`)



          目前有2個解決方案.

          第一個方案

          Field charsLocal = JSON.class.getDeclaredField("charsLocal");charsLocal.setAccessible(true);
          if (charsLocal.get(null) instanceof ThreadLocal) { ThreadLocal threadLocal = (ThreadLocal) charsLocal.get(null); threadLocal.remove();}

          通過反射的方式,?拿到charsLocal屬性, 主動調(diào)用它的remove()方法.

          但這種方案并不是最好的方案.?為了提高性能, 不得不把一些事先創(chuàng)建好的char[] 放入到線程的ThreadLocalMap中,?但是如果放入的太多又會造成內(nèi)存泄漏太多.?? 既不能避免內(nèi)存泄漏, 又不能泄漏太多,?就是下面的第二個方案.


          第二個方案

          設(shè)定char[]數(shù)組的最大長度=128, 假如程序使用了超過128大小的內(nèi)存,?那么會自動將char[]長度降到128大小, 保證char[]數(shù)組的長度不會超過128,?做到可控.

          Log4j作為一個日志框架, 在它的低版本中, 也存在大量內(nèi)存泄漏,?也是因為ThreadLoal的原因.?作為日志框架,必然要使用ThreadLocal來提高性能. 但是在Log4j的高版本中, 針對大量內(nèi)存泄漏的情況, 做了優(yōu)化, 超過最大值,就進行縮容.?也就是按照我們這里說的第二個方案.?部分源碼如下


          //源碼類?org.apache.logging.log4j.message.ParameterizedMessagepublic String getFormattedMessage() {    if (this.formattedMessage == null) {        StringBuilder buffer = getThreadLocalStringBuilder();        this.formatTo(buffer);        this.formattedMessage = buffer.toString();        // 進行縮容        StringBuilders.trimToMaxSize(buffer, Constants.MAX_REUSABLE_MESSAGE_SIZE);????}    return this.formattedMessage;}
          public static void trimToMaxSize(StringBuilder stringBuilder, int maxSize) {????// 超過設(shè)定的默認最大值, 就進行縮容 if (stringBuilder != null && stringBuilder.capacity() > maxSize) { stringBuilder.setLength(maxSize); stringBuilder.trimToSize(); }
          }


          個人猜測,?fastjson大概率也會采取第二個方案, 或者它不理睬這個內(nèi)存泄漏,?也不好說.


          祝大家2022新年快樂!



          瀏覽 69
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产午夜成人视频 | 黄片视频免费在线观看 | 亚洲精品福利导航 | 国产强 暴 疼 哭 处 | 国产AV综合 |