Redis订阅模式在生产环境引起的内存泄漏
内存泄漏
内存泄漏指的就是在运行过程中定义的各种各样的变量无法被垃圾回收器正常标记为不可达并触发后续的回收流程,主要原因还是因为对可回收对象引用没有去除,导致垃圾回收器通过GC ROOT可达性分析时认为当前是可达的;这时随着系统的运行时间,累积的不可回收的对象就越多,直到垃圾回收器执行Full GC还是没有空余空间存放新加入的对象,这时虚拟机就会抛出out of memory错误。此种错误可以分类为内存泄漏导致的,原因是应该回收的对象无法被垃圾回收器正常回收从而导致内存不足。说起内存泄漏近十年引起比较大的是便是Android 5.0引起的内存问题,该Bug导致手机在使用一段时间后必须手动重启系统释放内存;不然,无法运行任何应用,包括系统自带APPS桌面等都会引起FC崩溃;这时查看内存占用发现可用内存为负数。安卓5.0导致的内存泄漏:http://www.lupaworld.com/portal.php?mod=view&aid=249186&continueFlag=6f56029cba978a1a4ac09c91b20c196d
接下来说一个我在实际开发中文件遇到的内存泄漏问题,该问题在测试环境不易发现,主要原因有以下几点:
1、测试环境经常更新重启,相当于GC回收了对象
2、用户量太少了,根本撑不到内存泄露出现的那一刻
但是,生产环境那就不一样了,用户多,运行时间久,如果存在长期没有被回收的对象时,久而久之就会触发内存不足的情况
言归正传,生产环境出现的内存泄露问题是由对Redis订阅使用不当导致,下面我把引起内存泄漏的代码贴上来
1 /**
2 * 因为@ServerEndpoint不支持注入,所以使用SpringUtils获取IOC实例
3 */
4 private StringRedisTemplate redisTampate = SpringUtils.getBean(StringRedisTemplate.class);
5 private RedisMessageListenerContainer redisMessageListenerContainer = SpringUtils.getBean(RedisMessageListenerContainer.class);
6 private Session session;
7
8 @OnOpen
9 public void onOpen(Session session, @PathParam("topic") String topic, @PathParam("username") String username) {
11 this.session = session;
12 sessions.add(this);
13 SubscribeListener subscribeListener = new SubscribeListener();
14 subscribeListener.setSession(session);
15 subscribeListener.setStringRedisTemplate(redisTampate);
17 try {
18 redisMessageListenerContainer.addMessageListener(subscribeListener, new ChannelTopic(topic));
19 } catch (Exception e) {
20 e.printStackTrace();
21 }
22 }
这是一个WebSocket的项目,利用即时通信的特性实现了,由后台触发前端页面的刷新
眼尖的人应该已经发现问题所在了吧?这就是一个使用Spring和Redis不当导致的内存泄露问题
接下来我们分析
首先代码的4到7行申明了三个成员变量,主要关注点还是第5行的RedisMessageListenerContainer 变量,从SpringContext中取出了Redis的消息监听容器;在接下来的onOpen方法里定义了获取了WebSocket连接成功后产生而Session会话,这里的Session会话不是WebSession而是WebSocketSession,可以定义正会话帧,每次用户连接成功之后服务器就分发一个WebSocket给当前用户,当断开连接时该会话帧就会断开对象引用,垃圾回收器就可以回收;说到这里其实问题已经非常明显了,那就这个WebSession压根就没有被垃圾回收器回收掉,每次用户连接就产生一个WebSession对象,并通过地14行代买引用给Redis的监听器,然后再由将监听器添加到Redis消息监听容器中,而Redis消息监听容器又是从SpringContext中取出的,那就意味着该对象是一个SpringIOC中的Bean实例,这一个有GC ROOT引用的对象;这样一来后续产生的每一个WebSession会话帧都会被Redis消息监听容器的实例引用,垃圾回收器在进行可达性分析时都认为该对象是可达的,判定无法回收,从而就导致了内存泄漏。
这个问题其实是对垃圾回收器和Spring原理不了解导致的,在日常开发中应该尽可能的避免这些问题
Redis订阅模式在生产环境引起的内存泄漏的更多相关文章
- 生产环境Java应用服务内存泄漏分析与解决
有个生产环境CRM业务应用服务,情况有些奇怪,监控数据显示内存异常.内存使用率99.%多.通过生产监控看板发现,CRM内存超配或内存泄漏的现象,下面分析一下这个问题过程记录. 服务器配置情况: 生产服 ...
- 【原】Storm Local模式和生产环境中Topology运行配置
Storm入门教程 1. Storm基础 Storm Storm主要特点 Storm基本概念 Storm调度器 Storm配置 Guaranteeing Message Processing(消息处理 ...
- Centos6.3 下使用 Tomcat-6.0.43 非root用户 jsvc模式部署 生产环境 端口80 vsftp
一.安装JDK环境 方法一. 官方下载链接 http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260 ...
- redis 编译安装(生产环境推荐)
一.安装redis 1.下载redis包 wget http://download.redis.io/releases/redis-3.2.1.tar.gz 2.解压redis包到/opt下 tar ...
- Linux Debugging (九) 一次生产环境下的“内存泄露”
一个偶然的机会,发现一个进程使用了超过14G的内存.这个进程是一个RPC server,只是作为中转,绝对不应该使用这么多内存的.即使并发量太多,存在内存中的数据太多,那么在并发减少的情况下,这个内存 ...
- prometheus+grafana 监控生产环境机器的系统信息、redis、mongodb以及jmx
介绍: 为了更好的对生产环境的一些中间件和操作系统的运行情况进行可视化的展示,近期了解了下prometheus加上grafana来实现这种效果,由于prometheus是新出来的开源项目,所以,监控的 ...
- Centos6.3 下使用 Tomcat-6.0.43 非root用户 部署 生产环境 端口转发方式
一.安装JDK环境 方法一. 官方下载链接 http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260 ...
- 生产环境上,哨兵模式集群Redis版本升级应用实战
背景: 由于生产环境上所使用的Redis版本并不一致,好久也没有更新,为了避免版本不同对Redis集群造成影响,从而升级为统一Redis版本! 1.集群架构 一主两从三哨兵: 2.升级方案 (1)升级 ...
- ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现
ASP.NET MVC 学习笔记-2.Razor语法 1. 表达式 表达式必须跟在“@”符号之后, 2. 代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...
- redis实现消息队列&发布/订阅模式使用
在项目中用到了redis作为缓存,再学习了ActiveMq之后想着用redis实现简单的消息队列,下面做记录. Redis的列表类型键可以用来实现队列,并且支持阻塞式读取,可以很容易的实现一个高性 ...
随机推荐
- C++ Lambda 快速上手
Lambda 听起来非常的牛逼,很容易就会联想到函数式编程或者 Lambda 演算这样的东西.但是在 C++里,没那么复杂,就把它当匿名函数用就好了 HelloWorld 对于降序排序,我们可以这样写 ...
- 机器学习 | 分类性能度量指标 : ROC曲线、AUC值、正确率、召回率
本篇博客的图源来自 zhwhong,转载仅作学习使用! 在分类任务中,人们总是喜欢基于错误率来衡量分类器任务的成功程度.错误率指的是在所有测试样例中错分的样例比例.实际上,这样的度量错误掩盖了样例如何 ...
- Zookeeper(3)---java客户端的使用
前面介绍了zk指令的使用,这里说一下java客户端中怎么使用这些指令 <dependency> <groupId>org.apache.zookeeper</groupI ...
- C#设计模式08——桥接模式的写法
什么是C#桥接模式?桥接模式是一种结构型设计模式,它可以将抽象部分与实现部分分离,使它们可以独立地变化.这种模式通过将实现细节从抽象类中分离出来,从而让它们可以根据需要独立变化. 为什么要使用C#桥接 ...
- 机器学习-无监督机器学习-SVD奇异值分解-24
[POC] 1. 奇异值分解的本质 特征值分解只能够对于方阵提取重要特征, Ax=λx λ为特征值 x为对应的特征向量 奇异值分解可以对于任意矩阵: 注意看中间的矩阵是一个对角矩阵,颜色越深越起作用- ...
- 面向对象C++学习总结
洛谷日记3 2023.5 面向对象C++ : 运算符重载 1.运算符重载 (1)n定义重载运算符和定义普通函数类似,只是该函数的名字是operator@,@表示要重载的运算符. MinInt oper ...
- RL 基础 | 如何搭建自定义 gym 环境
需实现的方法: __init__(self): 需定义 action_space 和 observation_space,使用 space.Box 之类来表示(from gym import spac ...
- PS去除PDF中的WPS 编辑试用水印
1. 问题 自己的学习资料.pdf被添加上了相关水印,导致阅读起来很不舒服 2. 解决方式(适用于白底黑字的pdf资料,去除水印) 2.1 初始图片如下: 2.2 打开PS,选择菜单栏中选择一项中的色 ...
- Java-Enum常量特定方法
OnJava8-Enum-常量特定方法 用枚举实现责任链模式 责任链(Chain Of Responsibility)设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条"链& ...
- [转帖]「开源摘星计划」Prometheus监控Harbor(二进制版)
推荐 原创 键客李大白2022-08-08 11:35:07博主文章分类:Harbor进阶实战(企业实战)著作权 文章标签云原生运维Harbor文章分类kubernetes云计算私藏项目实操分享阅读数 ...