欢迎光临

我们一直在努力
当前位置:首页 > 互联网 >

Redis订阅模式在生产环境引起的内存泄漏

日期:
后台-插件-广告管理-首页/栏目/内容广告位一(PC)
后台-插件-广告管理-首页/栏目/内容广告位一(手机)

内存泄漏

内存泄漏指的就是在运行过程中定义的各种各样的变量无法被垃圾回收器正常标记为不可达并触发后续的回收流程,主要原因还是因为对可回收对象引用没有去除,导致垃圾回收器通过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>) 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();
[!--empirenews.page--]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原理不了解导致的,在日常开发中应该尽可能的避免这些问题

后台-插件-广告管理-首页/栏目/内容广告位二(PC)
后台-插件-广告管理-首页/栏目/内容广告位二(手机)
后台-插件-广告管理-内容广告位三(PC)
后台-插件-广告管理-内容广告位三(手机)

相关阅读

后台-插件-广告管理-内容广告位四(PC)
后台-插件-广告管理-内容广告位四(手机)

聚合标签

热门文章

后台-插件-广告管理-侧边广告位一(PC)
后台-插件-广告管理-侧边广告位一(手机)
  • Windows主机中localhost与127.0.0.1的区别是什么?

  • localhost与127.0.0.1的区别是什么? 相信有人会说是本地IP,曾有人说,用127.0.0.1比localhost好,可以减少一次解析。 这个理解是错误的,其实这两者是有区别的。 localhost也叫l
  • c盘满了怎么清理垃圾而不误删

  • 今天分享的主题是:c盘爆满发出警告如何清理又不误删系统文件。如果你也不会的话就看看下面的经验吧。 c盘满了怎么清理垃圾而不误删 1、很多人在清理c盘垃圾的时候会误删
  • steam怎么退款?

  • 有的时候我们在steam上买了游戏,但是却发现自己的电脑无法加载这款游戏,这时候我们就会想到退款,那么steam如何退款呢?下面小编就来给大家介绍一下。 steam怎么退款? 1、在ste
  • 电脑怎么录屏?如何录制电脑屏幕操作?

  • 如何录制电脑屏幕操作,相信很多朋友们遇到过这种类似的问题,你们对于这类问题如何解决呢?下面就给大家分享一下个人经验,希望可以帮助到大家。 电脑怎么录屏? 方法一:手机录制。
  • 手机如何投屏到电脑?(手机投屏电脑方法)

  • 每次都有新手机发布会,总会提到采用多少英寸的屏幕,但是手机在大的屏幕,也没有手机投屏到电脑、电视的体验爽,下面就一起来看看手机如何投屏到电脑? 手机投屏电脑方法 1、打开
后台-插件-广告管理-侧边广告位二(PC)
后台-插件-广告管理-侧边广告位二(手机)

最新文章

  • Redis订阅模式在生产环境引起的内存泄漏

  • 内存泄漏内存泄漏指的就是在运行过程中定义的各种各样的变量无法被垃圾回收器正常标记为不可达并触发后续的回收流程,主要原因还是因为对可回收对象引用没有去除,导致垃圾回收
  • MySQL 启动错误 The server quit without updating PID file

  • 首先来说我是如何发现这个错误的,公司的网站需要修改一些东西,前端通知让我备份一下网站的数据库和目录。在我手动执行了备份任务2分钟后,前端告诉我网站打开提示数据库错误。
  • 一种轻量分表方案-MyBatis拦截器分表实践

  • 背景部门内有一些亿级别核心业务表增速非常快,增量日均100W,但线上业务只依赖近一周的数据。随着数据量的迅速增长,慢SQL频发,数据库性能下降,系统稳定性受到严重影响。本篇文章,
  • [postgres]配置主从异步流复制

  • 前言环境信息 IP 角色 操作系统 PostgreSQL版本 192.168.1.112 主库 Debian 12 15.3 192.168.1.113 从库 Debian 12 15.3 配置主从
  • SQL手工注入

  • 两要素 用户能够控制输入的内容 web应用把用户输入的内容,在没有经过过滤或者严格过滤的情况下带入到数据库中执行分类 GET和POST 整数型,字符型,搜索型万能密码’1 or 1
  • MySQL数据库精选(从入门使用到底层结构)

  • 基本使用MySQL通用语法及分类 DDL: 数据定义语言,用来定义数据库对象(数据库、表、字段) DML: 数据操作语言,用来对数据库表中的数据进行增删改 DQL: 数据查询语言,用来查询数据
后台-插件-广告管理-侧边广告位三(PC)
后台-插件-广告管理-侧边广告位三(手机)