主頁 >  其他 > 長連接Netty服務記憶體泄漏,看我如何一步步捉“蟲”解決

長連接Netty服務記憶體泄漏,看我如何一步步捉“蟲”解決

2023-04-24 07:48:48 其他

作者:京東科技 王長春

背景

事情要回顧到雙11.11備戰前夕,在那個風雨交加的夜晚,一個急促的咚咚報警,驚破了電閃雷鳴的黑夜,將沉浸在夢香,熟睡的我驚醒,

一看手機咚咚報警,不好!有大事發生了!電話馬上打給老板:

老板說: 長連接嗎?
我說:是的!
老板說:該來的還是要來的,最侄訓是來了,快,趕緊先把服務重啟下!
我說:已經重啟了!
老板說: 這問題必須給我解決了!
我說:必須的!

線上應用長連接Netty服務出現記憶體泄漏了!真讓人頭大

在這風雨交加的夜晚,此時,面對毫無頭緒的問題,以及迫切想攻克問題的心,已經讓我興奮不已,手一把揉揉付訓迷糊的眼,今晚又注定是一個不眠之夜!

應用介紹

說起支付業務的長連接服務,真是說來話長,我們這就長話短說

隨著業務及系統架構的復雜化,一些場景,用戶操作無法同步得到結果,一般采用的短連接輪訓的策略,客戶端需要不停的發起請求,時效性較差還浪費服務器資源,

短輪訓痛點:

  • 時效性差
  • 耗費服務器性能
  • 建立、關閉鏈接頻繁

相比于短連接輪訓策略,長連接服務可做到實時推送資料,并且在一個鏈接保持期間可進行多次資料推送,服務應用常見場景:PC端掃碼支付,用戶打開掃碼支付頁面,手機掃碼完成支付,頁面實時展示支付成功資訊,提供良好的用戶體驗,

長連服務優勢:

  • 時效性高提升用戶體驗
  • 減少鏈接建立次數
  • 一次鏈接多次推送資料
  • 提高系統吞吐量

長連接服務系統架構

這個長連接服務使用Netty框架,Netty的高性能為這個應用帶來了無上的榮光,承接了眾多長連接使用場景的業務:

  • PC收銀臺微信支付
  • 聲波紅包
  • POS線下掃碼支付

問題現象

回到線上問題,出現記憶體泄漏的是長連接前置服務,觀察線上服務,這個應用的記憶體泄漏的現象總伴隨著記憶體的增長,這個增長真是非常的緩慢,緩慢,緩慢,2、3個月內從30%慢慢增長到70%,極難發現

應用實體的記憶體總是在緩慢的增長

每次發生記憶體泄漏,記憶體快耗盡時,總得重啟下,雖說重啟是最快解決的方法,但是程式員是天生懶惰的,要數著日子來重啟,那絕對不是一個優秀程式員的行為!問題必須徹底解決!

問題排查與復現

排查

遇到問題,毫無頭緒,首先還是需要去案發第一現場,排查“死者(應用實體)”死亡現場,通過在發生FullGC的時間點,通過Digger查詢ERROR日志,沒想到還真找到破案的第一線索:

線上出現問題日志

io.netty.util.ResourceLeakDetector [176] - LEAK: ByteBuf.release() was not called before it's garbage-collected. Enable advanced leak reporting to find out where the leak occurred. To enable advanced leak reporting, specify the JVM option '-Dio.netty.leakDetection.level=advanced' or call ResourceLeakDetector.setLevel() See http://netty.io/wiki/reference-counted-objects.html for more information.

線上日志竟然有一個明顯的"LEAK"泄漏字樣,作為技術人的敏銳的技術嗅覺,和找Bug的直覺,可以確認,這就是事故案發第一現場,

我們憑借下大學四六級英文水平的,繼續翻譯下線索,原來是這吶!

ByteBuf.release() 在垃圾回收之前沒有被呼叫,啟用高級泄漏報告以找出泄漏發生的位置,要啟用高級泄漏報告,請指定 JVM 選項“-Dio.netty.leakDetectionLevel=advanced”或呼叫 ResourceLeakDetector.setLevel()

啊哈!這資訊不就是說了嘛!ByteBuf.release()在垃圾回收前沒有呼叫,有ByteBuf物件沒有被釋放,ByteBuf可是分配在直接記憶體的,沒有被釋放,那就意味著堆外記憶體泄漏,所以記憶體一直是非常緩慢的增長,GC都不能夠進行釋放,

提供了這個線索,那到底是我們應用中哪段代碼出現了ByteBuf物件的記憶體泄漏呢?
專案這么大,Netty通信處理那么多,怎么找呢?自己從中搜索,那肯定是不靠譜,找到了又怎么釋放呢?

復現

面對這一連三問?別著急,Netty的日志提示還是非常完善:啟用高級泄漏報告找出泄漏發生位置嘛,生產上不可能啟用,并且生產發生時間極長,時間上來不及,而且未經驗證,不能直接生產發布,那就本地代碼復現一下!找到具體代碼位置,

為了本地復現Netty泄漏,定位詳細的記憶體泄漏代碼,我們需要做這幾步:

1、配置足夠小的本地JVM記憶體,以便快速模擬堆外記憶體泄漏,
如圖,我們設定設定PermSize=30M, MaxPermSize=43M
IDEA配置本地JVM記憶體

2、模擬足夠多的長連接請求,我們使用Postman定時批量發請求,以達到服務的堆外記憶體泄漏,

啟動專案,通過JProfilerJVM監控工具,我們觀察到記憶體緩慢的增長,最終觸發了本地Netty的堆外記憶體泄漏,本地復現成功:

JProfilerJVM監控

復現線上生產問題

_那問題具體出現在代碼中哪塊呢?_我們最重要的是定位具體代碼,在開啟了Netty的高級記憶體泄漏級別為高級,來定位下:

3、開啟Netty的高級記憶體泄漏檢測級別,JVM引數如下:
-Dio.netty.leakDetectionLevel=advanced

IDEA配置本地JVM記憶體-增加DIO

再啟動專案,模擬請求,達到本地應用JVM記憶體泄漏,Netty輸出如下具體日志資訊,可以看到,具體的日志資訊比之前的資訊更加完善:

2020-09-24 20:11:59.078 [nioEventLoopGroup-3-1] INFO  io.netty.handler.logging.LoggingHandler [101] - [id: 0x2a5e5026, L:/0:0:0:0:0:0:0:0:8883] READ: [id: 0x926e140c, L:/127.0.0.1:8883 - R:/127.0.0.1:58920]
2020-09-24 20:11:59.078 [nioEventLoopGroup-3-1] INFO  io.netty.handler.logging.LoggingHandler [101] - [id: 0x2a5e5026, L:/0:0:0:0:0:0:0:0:8883] READ COMPLETE
2020-09-24 20:11:59.079 [nioEventLoopGroup-2-8] ERROR io.netty.util.ResourceLeakDetector [171] - LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
WARNING: 1 leak records were discarded because the leak record count is limited to 4. Use system property io.netty.leakDetection.maxRecords to increase the limit.
Recent access records: 5
#5:
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.readBytes(AdvancedLeakAwareCompositeByteBuf.java:476)
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.readBytes(AdvancedLeakAwareCompositeByteBuf.java:36)
	com.jd.jr.keeplive.front.service.nettyServer.handler.LongRotationServerHandler.getClientMassageInfo(LongRotationServerHandler.java:169)
	com.jd.jr.keeplive.front.service.nettyServer.handler.LongRotationServerHandler.handleHttpFrame(LongRotationServerHandler.java:121)
	com.jd.jr.keeplive.front.service.nettyServer.handler.LongRotationServerHandler.channelRead(LongRotationServerHandler.java:80)
	io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
	io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
	io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
	io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
	......
#4:
	Hint: 'LongRotationServerHandler#0' will handle the message from this point.
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:1028)
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:36)
	io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpMessage.touch(HttpObjectAggregator.java:359)
	......
#3:
	Hint: 'HttpServerExpectContinueHandler#0' will handle the message from this point.
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:1028)
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:36)
	io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpMessage.touch(HttpObjectAggregator.java:359)
  ......
#2:
	Hint: 'HttpHeartbeatHandler#0' will handle the message from this point.
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:1028)
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:36)
	io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpMessage.touch(HttpObjectAggregator.java:359)
  ......
#1:
	Hint: 'IdleStateHandler#0' will handle the message from this point.
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:1028)
	io.netty.buffer.AdvancedLeakAwareCompositeByteBuf.touch(AdvancedLeakAwareCompositeByteBuf.java:36)
	io.netty.handler.codec.http.HttpObjectAggregator$AggregatedFullHttpMessage.touch(HttpObjectAggregator.java:359)
  ......
Created at:
	io.netty.util.ResourceLeakDetector.track(ResourceLeakDetector.java:237)
	io.netty.buffer.AbstractByteBufAllocator.compositeDirectBuffer(AbstractByteBufAllocator.java:217)
	io.netty.buffer.AbstractByteBufAllocator.compositeBuffer(AbstractByteBufAllocator.java:195)
	io.netty.handler.codec.MessageAggregator.decode(MessageAggregator.java:255)
  ......

開啟高級的泄漏檢測級別后,通過上面例外日志,我們可以看到記憶體泄漏的具體地方:com.jd.jr.keeplive.front.service.nettyServer.handler.LongRotationServerHandler.getClientMassageInfo(LongRotationServerHandler.java:169)

記憶體泄漏代碼快

不得不說Netty記憶體泄漏排查這點是真香!真香好評!

問題解決

找到問題了,那我么就需要解決,如何釋放ByteBuf記憶體呢?

如何回收泄漏的ByteBuf

其實Netty官方也針對這個問題做了專門的討論,一般的經驗法則是,最后訪問參考計數物件的一方負責銷毀該參考計數物件,具體來說:

  • 如果一個[發送]組件將一個參考計數的物件傳遞給另一個[接收]組件,則發送組件通常不需要銷毀它,而是由接收組件進行銷毀,

  • 如果一個組件使用了一個參考計數的物件,并且知道沒有其他物件將再訪問它(即,不會將參考傳遞給另一個組件),則該組件應該銷毀它,

詳情請看翻譯的Netty官方檔案對參考計數的功能使用:

【翻譯】Netty的物件參考計數
【原文】Reference counted objects

總結起來主要三個方式
方式一:手動釋放,哪里使用了,使用完就手動釋放,
方式二:升級ChannelHandlerSimpleChannelHandler, 在SimpleChannelHandler中,Netty對收到的所有訊息都呼叫了ReferenceCountUtil.release(msg)
方式三:如果處理程序中不確定ByteBuf是否應該被釋放,那交給Netty的ReferenceCountUtil.release(msg)來釋放,這個方法會判斷背景關系是否可以釋放,

考慮到長連接前置應用使用的是ChannelHandler,如果升級SimpleChannelHandler對現有API介面變動比較大,同時如果手動釋放,不確定是否應該釋放風險也大,因此使用方式三,如下:

修復代碼

線上實體記憶體正常

問題修復后,線上服務正常,記憶體使用率也沒有再出現因泄漏而增長,從線上我們增加的日志中看出,FullHttpRequestByteBuf記憶體釋放成功,從此長連接前置記憶體泄漏的問題徹底解決

線上服務記憶體釋放成功

總結

一、Netty的記憶體泄漏排查其實并不難,Netty提供了比較完整的排查記憶體泄漏工具

JVM 選項-Dio.netty.leakDetection.level

目前有 4 個泄漏檢測級別的:

  • DISABLED - 完全禁用泄漏檢測,不推薦

  • SIMPLE - 抽樣 1% 的緩沖區是否有泄漏,默認

  • ADVANCED - 抽樣 1% 的緩沖區是否泄漏,以及能定位到緩沖區泄漏的代碼位置

  • PARANOID - 與 ADVANCED 相同,只是它適用于每個緩沖區,適用于自動化測驗階段,如果生成輸出包含“LEAK:”,則可能會使生成失敗,

本次記憶體泄漏問題,我們通過本地設定泄漏檢測級別為高級,即:-Dio.netty.leakDetectionLevel=advanced定位到了具體記憶體泄漏的代碼,

同時Netty也給出了避免泄漏的最佳實踐

  • 在 PARANOID 泄漏檢測級別以及 SIMPLE 級別運行單元測驗和集成測驗,

  • 在 SIMPLE 級別向整個集群推出應用程式之前,請先在相當長的時間內查看是否存在泄漏,

  • 如果有泄漏,灰度發布中使用 ADVANCED 級別,以獲得有關泄漏來源的一些提示,

  • 不要將泄漏的應用程式部署到整個群集,

二、解決Netty記憶體泄漏,Netty也提供了指導方案,主要有三種方式

方式一:手動釋放,哪里使用了,使用完就手動釋放,這個對使用方要求比較高了
方式二:如果處理程序中不確定ByteBuf是否應該被釋放,那交給NettyReferenceCountUtil.release(msg)來釋放,這個方法會判斷背景關系中是否可以釋放,簡單方便
方式三:升級ChannelHandlerSimpleChannelHandler, 在SimpleChannelHandler中,Netty對收到的所有訊息都呼叫了ReferenceCountUtil.release(msg)升級介面,可能對現有API改動會比較大

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/550938.html

標籤:其他

上一篇:面試官最常問的10道測驗用例和5道思維面試題及答案,每1題都很經典

下一篇:返回列表

標籤雲
其他(157921) Python(38094) JavaScript(25383) Java(17988) C(15215) 區塊鏈(8258) C#(7972) AI(7469) 爪哇(7425) MySQL(7137) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4558) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2430) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1959) Web開發(1951) HtmlCss(1921) python-3.x(1918) 弹簧靴(1913) C++(1910) xml(1889) PostgreSQL(1872) .NETCore(1854) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 長連接Netty服務記憶體泄漏,看我如何一步步捉“蟲”解決

    事情要回顧到雙11.11備戰前夕,在那個風雨交加的夜晚,一個急促的咚咚報警,驚破了電閃雷鳴的黑夜,將沉浸在夢香,熟睡的我驚醒。 ......

    uj5u.com 2023-04-24 07:48:48 more
  • 面試官最常問的10道測驗用例和5道思維面試題及答案,每1題都很經典

    軟體測驗面試中,測驗用例是非常容被問到的一個點,今天就給大家把最常見的20道測驗用例方面的問題給大家整理出來,希望對大家的面試提供幫助。 ......

    uj5u.com 2023-04-24 07:48:23 more
  • 從熱愛到深耕,全國Top10開源軟體出品人手把手教你如何做開源

    摘要:DTT直播邀請到管雷鳴與廣大開發者分享“如何在開源領域找到適合自己的路”。 “想象一下,你寫的代碼被越來越多的人使用,并極大地幫助他們提高了開發效率和穩定性。”這是不是一件很酷的事?而這正是開源的魅力… 開源作為一種推動軟體開發技術創新的新模式,廣受開發者的喜愛。作為擁有40余個開源專案,全國 ......

    uj5u.com 2023-04-24 07:47:21 more
  • 性能測驗工具Locust和JMeter比較-及相關書籍下載

    Apache JMeter?和Locust都是是最受歡迎的性能測驗工具。 JMeter和Locust - 簡介 JMeter是久經考驗的性能框架之一,其第一個版本大約在20年前發布。 它是用純Java語言撰寫的。 最初,JMeter開發用于執行Web和FTP應用程式的負載測驗。 但是,現在它允許測驗 ......

    uj5u.com 2023-04-24 07:47:03 more
  • 從業4年的軟體測驗工程師,你只會點點點?我勸您轉行吧.....

    我越來越擔心我作為一個測驗工程師的未來。 恍然間,發現自己在這個行業里已經摸爬滾打了五年了,原以為自己就憑已有的專案經驗和作業經歷怎么著也應該算得上是一個業內比較資歷的人士了,但是今年在換作業的程序中卻遭到了重大的挫折。詳細程序我就不再敘述,在此,只想給大家說一說被拒絕的原因,看看大家有沒有相似的經 ......

    uj5u.com 2023-04-24 07:46:42 more
  • Vulnhub之 BoredHackerBlog: Social Network 2.0靶機詳細測驗程

    Socnet 作者:jason huawen 靶機資訊 名稱:BoredHackerBlog: Social Network 2.0 地址: https://www.vulnhub.com/entry/boredhackerblog-social-network-20,455/ 識別目標主機IP地址 ......

    uj5u.com 2023-04-24 07:46:05 more
  • NB-iot模塊可做財物防盜竊器,讓你的財物可定位跟蹤!

    NB-iot無線數傳模塊可做財物防盜竊器,讓你的財物可定位跟蹤! 隨著社會的發展,公共資源及共享資源的蓬勃發展,對資產管理和資產追蹤有了新的需求,如:某兒童玩具車在商場外面提供車輛乘坐游玩服務,但是擔心玩具車輛被盜竊等資產管理、資產追蹤的問題。 要是有一種神器可以監管這些資產就好了!能夠劃定資產應用 ......

    uj5u.com 2023-04-24 07:45:59 more
  • Vulnhub之Harrison靶機詳細測驗程序(提權成功)

    Harrison 作者:jason huawen 靶機資訊 名稱: SP: harrison 地址: https://www.vulnhub.com/entry/sp-harrison,302/ 識別目標主機IP地址 ─(kali?kali)-[~/Vulnhub/Harrison] └─$ sud ......

    uj5u.com 2023-04-24 07:45:54 more
  • 常見的webshell連接工具流量

    中國菜刀 連接程序中使用base64編碼對發送的指令進行加密,其中兩個關鍵payload z1 和 z2,名字都是可變的。 然后還有一段以QG開頭,7J結尾的固定代碼。 蟻劍 默認的user-agent請求頭是antsword xxx,不過可以修改。 一般將payload進行分段,然后分別進行bas ......

    uj5u.com 2023-04-23 07:46:06 more
  • 劍指 Offer 33. 二叉搜索樹的后序遍歷序列(java解題)

    leetcode《圖解資料結構》劍指 Offer 33. 二叉搜索樹的后序遍歷序列(java解題)的解題思路和java代碼,并附上java中常用資料結構的功能函式。 ......

    uj5u.com 2023-04-23 07:46:02 more