热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

服务器环境8核32G内存问题:在5000个连接的时候Tomcat内存基本吃满Tomcat压测:连接数内存消耗CPU10006.9G100%2000

服务器环境8核 32G内存

问题:

在5000个连接的时候Tomcat内存基本吃满

Tomcat 压测:

 

连接数

内存消耗

CPU

1000

6.9G

100%

2000

12G

100%

3000

19G

100%

4000

25G

100%

4468

30G

100%

更多连接已经无法建立

 

 

 

检查下JVM内存使用情况,其中老年代被占用了98.4%,有大量不能释放的对象在heap。

老年代内存大小31.5G,老年代使用31G

 

 

JETTY压测

连接数

内存消耗

CPU

1000

1G

25%

3000

1G

25%

5000

1.1G

25%

10000

1.2G

25%

20000

1.4G

50%

 

内存情况老年代被使用了79.4%,老年代总大小3.5G占用0.5G

通过现象我们可以看到jetty占用内存非常小,而TOMCAT暂用却非常多,但是国外论坛有人Tomcat却可以压到4万的连接,是什么东西占用了这么多heap空间呢?

 

分析TOMCAT内存占满原因:

一,由于测试方便在本地启动程序建立了501个连接,并且用jmap生成了快照

二,我们用mat来分析下内存的情况(也可以用jhat,但是太low了很多还需要人工肉眼看和计算)

 

我们可以看到WsFrameServer占用了2.9的heap空间对象个数恰好是我们建立的连接数

三,现在我们来分析WsFrameServer对象,到底什么东西可以占用这么大

我们可以看到WsFrameServer对象直接引用对象的heap空间HeapCharBuffer和HeapByteBuffer非常大

我们再来看看这个大对象什么引用在引用,通过分析我们知道了原来是WsFrameServer的messageBufferText成员变量

下面我们来看下源代码

我们在WsFrameServer的父类中发现了这两个大对象的引用

那么问题来了,是什么原因导致这个对象很大的呢?我们继续看源代码什么地方用来它,特别是初始化的时候

我们检查到,这个地方初始化的,初始化大小是wsSession.getMaxBinaryMessageBufferSize()

和wsSession.getMaxTextMessageBufferSize(),那么问题又来了,这两个值有是从哪里来的呢?

我们查看源码

有一个默认值是8K,如果是8K的话内存不至于溢出,看什么地方做了赋值

原来是这个地方做的赋值,那么webSocketContainer又是从哪里来的呢?

我们点进去

这里要么是默认值,要么是什么地方做了设置我们打断点调试,而且这个默认值是8K,肯定是什么地方修改了,那么我们在set方法打断点

断点来了,我们通过线程栈来分析下什么地方调到这里来的,跟着往上点

最后我们发现是这个类ServletServerContainerFactoryBean,这个类是spring提供的,我们是在这儿用到了,原来如此,内存之所以这么大就是这里的设置导致的,这个设置的目的是让websocket可以传输更大的消息

其实我们看到的Tomcat的webSocketContainer是实现了javax.websocket.webSocketContainer的,很明显这个是J2EE的规范我们可以查下这个规范

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

其实这个类就是在初始化的时候可以让你设置websocket相关的一些参数

但是它设置了之后对所有session都生效了所以导致我们的连接数上不去,有什么办法可以解决吗,我们查到有另外的J2EE规范可以在运行过程中动态的修改而且是针对特定session的

那么问题来了,为什么jetty没有出现这个问题,如果是J2EE的规范那么我们设置这个值JETTY也应该出现这个问题,可是没有!

我们再来对jetty进行调试,发现这个配置对jetty不起作用

为什么不起作用呢?这又是另外的问题了~

后来通过源码分析得知JETTY和TOMCAT的实现不一样,不知道算不算BUG,个人认为是JETTY的BUG~

什么代码实现导致他们不一样呢?

Tomcat每次请求过来时在创建session时都会把这个webSocketContainer作为参数传进去所以对所有的session都生效了

我们来看看jetty

启动初始化时jetty把webSocketContainer的参数值设置给了这个过滤器,我们看看这个过滤器它的dofilter方法

其实在这个过滤器我们没有注册任何的访问URL,因为我们是通过spring提供的方式实现的websocket,如果我们在这个过滤器注册了访问URL那么所有过来的请求都会生效~可以继续跟后面的代码,其实就是调用的其他处理器来处理,这些处理器是在这里初始化的

每个url都有一个单独的处理器,这个实现是springboot提供的

spring给每一个websocket URL单独new 了一个处理器,jetty里面这个类是WebSocketServerFactory

其实jetty的处理方式是事件驱动模式设计,把所有的请求当做一个事件,不同的事件有自己对应的eventdriver来处理

重点是jetty在实例化这个对象的时候并没有把webSocketContainer所带的参数设置进去

这就导致了Tomcat生效jetty没有生效,其实你还会发现虽然jetty的buffer默认大小是64K,Tomcat是8K,可是jetty压测的时候CPU和内存都比Tomcat少,这是为什么呢?

原因是jetty用了对象池,不像tomcat来一次请求就new一个buffer,下面是jetty使用对象池的地方

后面简单做了netty的压测10000个连接消耗内存190M,吊炸天的存在


推荐阅读
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • JavaScript简介及语言特点
    本文介绍了JavaScript的起源和发展历程,以及其在前端验证和服务器端开发中的应用。同时,还介绍了ECMAScript标准、DOM对象和BOM对象的作用及特点。最后,对JavaScript作为解释型语言和编译型语言的区别进行了说明。 ... [详细]
  • 本文介绍了使用数据库管理员用户执行onstat -l命令来监控GBase8s数据库的物理日志和逻辑日志的使用情况,并强调了对已使用的逻辑日志是否及时备份的重要性。同时提供了监控方法和注意事项。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有