日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

TOMCAT websocket 多连接内存泄漏与jetty对比分析

發(fā)布時(shí)間:2024/4/13 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 TOMCAT websocket 多连接内存泄漏与jetty对比分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

服務(wù)器環(huán)境8核 32G內(nèi)存

?

問題:

在5000個(gè)連接的時(shí)候Tomcat內(nèi)存基本吃滿

Tomcat 壓測:

連接數(shù)

內(nèi)存消耗

CPU

1000

6.9G

100%

2000

12G

100%

3000

19G

100%

4000

25G

100%

4468

30G

100%

更多連接已經(jīng)無法建立

檢查下JVM內(nèi)存使用情況,其中老年代被占用了98.4%,有大量不能釋放的對象在heap。

老年代內(nèi)存大小31.5G,老年代使用31G

JETTY壓測

連接數(shù)

內(nèi)存消耗

CPU

1000

1G

25%

3000

1G

25%

5000

1.1G

25%

10000

1.2G

25%

20000

1.4G

50%

內(nèi)存情況老年代被使用了79.4%,老年代總大小3.5G占用0.5G

通過現(xiàn)象我們可以看到j(luò)etty占用內(nèi)存非常小,而TOMCAT暫用卻非常多,但是國外論壇有人Tomcat卻可以壓到4萬的連接,是什么東西占用了這么多heap空間呢?

分析TOMCAT內(nèi)存占滿原因:

一,由于測試方便在本地啟動(dòng)程序建立了501個(gè)連接,并且用jmap生成了快照

二,我們用mat來分析下內(nèi)存的情況(也可以用jhat,但是太low了很多還需要人工肉眼看和計(jì)算)

我們可以看到WsFrameServer占用了2.9的heap空間對象個(gè)數(shù)恰好是我們建立的連接數(shù)

三,現(xiàn)在我們來分析WsFrameServer對象,到底什么東西可以占用這么大

我們可以看到WsFrameServer對象直接引用對象的heap空間HeapCharBuffer和HeapByteBuffer非常大

我們再來看看這個(gè)大對象什么引用在引用,通過分析我們知道了原來是WsFrameServer的messageBufferText成員變量

下面我們來看下源代碼

我們在WsFrameServer的父類中發(fā)現(xiàn)了這兩個(gè)大對象的引用

那么問題來了,是什么原因?qū)е逻@個(gè)對象很大的呢?我們繼續(xù)看源代碼什么地方用來它,特別是初始化的時(shí)候

我們檢查到,這個(gè)地方初始化的,初始化大小是wsSession.getMaxBinaryMessageBufferSize()

和wsSession.getMaxTextMessageBufferSize(),那么問題又來了,這兩個(gè)值有是從哪里來的呢?

我們查看源碼

有一個(gè)默認(rèn)值是8K,如果是8K的話內(nèi)存不至于溢出,看什么地方做了賦值

原來是這個(gè)地方做的賦值,那么webSocketContainer又是從哪里來的呢?

我們點(diǎn)進(jìn)去

這里要么是默認(rèn)值,要么是什么地方做了設(shè)置我們打斷點(diǎn)調(diào)試,而且這個(gè)默認(rèn)值是8K,肯定是什么地方修改了,那么我們在set方法打斷點(diǎn)

斷點(diǎn)來了,我們通過線程棧來分析下什么地方調(diào)到這里來的,跟著往上點(diǎn)

最后我們發(fā)現(xiàn)是這個(gè)類ServletServerContainerFactoryBean,這個(gè)類是spring提供的,我們是在這兒用到了,原來如此,內(nèi)存之所以這么大就是這里的設(shè)置導(dǎo)致的,這個(gè)設(shè)置的目的是讓websocket可以傳輸更大的消息

其實(shí)我們看到的Tomcat的webSocketContainer是實(shí)現(xiàn)了javax.websocket.webSocketContainer的,很明顯這個(gè)是J2EE的規(guī)范我們可以查下這個(gè)規(guī)范

https://docs.oracle.com/javaee/7/api/javax/websocket/WebSocketContainer.html

其實(shí)這個(gè)類就是在初始化的時(shí)候可以讓你設(shè)置websocket相關(guān)的一些參數(shù)

但是它設(shè)置了之后對所有session都生效了所以導(dǎo)致我們的連接數(shù)上不去,有什么辦法可以解決嗎,我們查到有另外的J2EE規(guī)范可以在運(yùn)行過程中動(dòng)態(tài)的修改而且是針對特定session的

那么問題來了,為什么jetty沒有出現(xiàn)這個(gè)問題,如果是J2EE的規(guī)范那么我們設(shè)置這個(gè)值JETTY也應(yīng)該出現(xiàn)這個(gè)問題,可是沒有!

我們再來對jetty進(jìn)行調(diào)試,發(fā)現(xiàn)這個(gè)配置對jetty不起作用

為什么不起作用呢?這又是另外的問題了~

后來通過源碼分析得知JETTY和TOMCAT的實(shí)現(xiàn)不一樣,不知道算不算BUG,個(gè)人認(rèn)為是JETTY的BUG~

什么代碼實(shí)現(xiàn)導(dǎo)致他們不一樣呢?

Tomcat每次請求過來時(shí)在創(chuàng)建session時(shí)都會(huì)把這個(gè)webSocketContainer作為參數(shù)傳進(jìn)去所以對所有的session都生效了

我們來看看jetty

啟動(dòng)初始化時(shí)jetty把webSocketContainer的參數(shù)值設(shè)置給了這個(gè)過濾器,我們看看這個(gè)過濾器它的dofilter方法

其實(shí)在這個(gè)過濾器我們沒有注冊任何的訪問URL,因?yàn)槲覀兪峭ㄟ^spring提供的方式實(shí)現(xiàn)的websocket,如果我們在這個(gè)過濾器注冊了訪問URL那么所有過來的請求都會(huì)生效~可以繼續(xù)跟后面的代碼,其實(shí)就是調(diào)用的其他處理器來處理,這些處理器是在這里初始化的

每個(gè)url都有一個(gè)單獨(dú)的處理器,這個(gè)實(shí)現(xiàn)是springboot提供的

spring給每一個(gè)websocket URL單獨(dú)new 了一個(gè)處理器,jetty里面這個(gè)類是WebSocketServerFactory

其實(shí)jetty的處理方式是事件驅(qū)動(dòng)模式設(shè)計(jì),把所有的請求當(dāng)做一個(gè)事件,不同的事件有自己對應(yīng)的eventdriver來處理

重點(diǎn)是jetty在實(shí)例化這個(gè)對象的時(shí)候并沒有把webSocketContainer所帶的參數(shù)設(shè)置進(jìn)去

這就導(dǎo)致了Tomcat生效jetty沒有生效,其實(shí)你還會(huì)發(fā)現(xiàn)雖然jetty的buffer默認(rèn)大小是64K,Tomcat是8K,可是jetty壓測的時(shí)候CPU和內(nèi)存都比Tomcat少,這是為什么呢?

原因是jetty用了對象池,不像tomcat來一次請求就new一個(gè)buffer,下面是jetty使用對象池的地方

后面簡單做了netty的壓測10000個(gè)連接消耗內(nèi)存190M,吊炸天的存在

總結(jié)

以上是生活随笔為你收集整理的TOMCAT websocket 多连接内存泄漏与jetty对比分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。