一、redis资源未释放的起因:

N年前,在修改一个古老程序时,不小心把redis释放的这块给干掉了,

if (jedis != null) {
if (!isInProcess) {
jedis.del(currentPageRunControlRedisKey);
}
JedisUtil.getInstance().closeJedis(jedis);
}

程序调用了一会之后,就获取不到redis连接了,异常如下:

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:42)

对比代码,定位到问题之后,修复上线。

二、事后分析出错的原因:

1、对于redis的认知不足.

2、java从集成redis角度上,我的认知:

2.1、选择spring-data-redis集成,目前我们的osp框架支持我们用这种方式,我目前的项目在用(po服务化).

集成后用RedisTemplate即可来操作。

好处:spring来帮你管理redis的连接获取和释放,我们只需要关注自己的业务就好.

坏处:限制于spring框架,其他暂未感觉...

2.2、用jedis来操作吧,

自己写好一个类,来获取JedisPool,对于redis的操作,记住操作完成后,释放连接回连接池,否则就会发生,我这次发生的这种问题。

好处:操作上更加灵活,不限于spring。

坏处:容易出错。

三、改进:

对于资源未释放,想到了在io操作,db操作等情况,最好封装统一的方法,保证最后资源一定是释放的。

redis方面,我参考spring的redisTemplate,

封装一个redis工具类,对每种类型的redis操作,封装一个方法,操作完后将资源释放回连接池,可避免再忘记释放redis。

代码示例:         

 import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; /**
* 描 述:JedisUtil
* 作 者:潇邦
*/
public class JedisUtil { private static final Log logger = LogFactory.getLog(JedisUtil.class); //Redis服务器IP
private static String IP = "127.0.0.1"; //Redis的端口号
private static int PORT = 6379; //可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = 64; //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 20; //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = 3000; private static int TIMEOUT = 3000; //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true; //在return给pool时,是否提前进行validate操作;
private static boolean TEST_ON_RETURN = true; private static Map<String, JedisPool> maps = new ConcurrentHashMap<String, JedisPool>(); private JedisUtil() {
} /**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
*/
private static class RedisUtilHolder {
private static JedisUtil instance = new JedisUtil();
} /**
* 当getInstance方法第一次被调用的时候,它第一次读取 RedisUtilHolder.instance,导致RedisUtilHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静
* 态域,从而创建RedisUtil的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。 这个模式的优势在于,getInstance方法并没有被同步,
* 并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本。
*/
public static JedisUtil getInstance() {
return RedisUtilHolder.instance;
} /**
* 获取连接池.
*/
private JedisPool getPool(String ip, int port) {
String key = ip + ":" + port;
JedisPool pool = null;
if (!maps.containsKey(key)) {//根据ip和端口判断连接池是否存在.
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
config.setTestOnReturn(TEST_ON_RETURN);
try {
pool = new JedisPool(config, ip, port, TIMEOUT);
maps.put(key, pool);
} catch (Exception e) {
logger.error("初始化Redis连接池异常:", e);
}
} else {
pool = maps.get(key);
}
return pool;
} /**
* 获取Jedis实例
*/
public Jedis getJedis() {
Jedis jedis = null;
try {
jedis = getPool(IP, PORT).getResource();
} catch (Exception e) {
logger.error("获取Jedis实例异常:", e);
// 销毁对象
getPool(IP, PORT).returnBrokenResource(jedis);
}
return jedis;
} /**
* 释放jedis资源到连接池
*/
public void returnResource(final Jedis jedis) {
if (jedis != null) {
getPool(IP, PORT).returnResource(jedis);
}
} /**
* 获取数据
*/
public Object get(String key) {
Object value = null;
Jedis jedis = null;
try {
jedis = getJedis();
value = jedis.get(key);
} catch (Exception e) {
logger.warn("获取数据异常:", e);
} finally {
//返还到连接池
returnResource(jedis);
}
return value;
} public static void main(String[] args) {
Object val = JedisUtil.getInstance().get("redisKey");
System.out.println(val);
} }

四、redis的概念:

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

五、数据库连接池的概念:

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

六、参考的资料:

http://www.cnblogs.com/linjiqin/archive/2013/06/14/3135248.html

http://www.sjsjw.com/kf_www/article/70_11941_26800.asp

http://www.cnblogs.com/tankaixiong/p/3660075.html

http://blog.csdn.net/truong/article/details/46711045

http://my.oschina.net/ydsakyclguozi/blog/465859

http://blog.csdn.net/aacm1992/article/details/21977237

http://www.cnblogs.com/jifeng/p/4676863.html

redis资源未释放引发的问题的更多相关文章

  1. 解决切换场景时NGUI图集资源未释放的问题

    使用unity3d编辑器,在切换场景的时候.NGUI的图集没有释放造成内存不足游戏闪退的问题. 默认情况下,unity3d切换场景之后会释放不用的内存,即内部会调用Resources.UnloadUn ...

  2. 使用HttpURLConnection时遇到的资源未释放的问题

    http://blog.sina.com.cn/s/blog_56beadc60100j9zu.html 今天自己写了一个压力测试的小程序,同时启100个线程,每个线程都串行地访问应用服务器上的一个j ...

  3. 图层损坏 E/ArcGIS﹕ The map or layer has been destroyed or recycled. 资源未释放

    看到论坛上有个网友和我一样的问题: The map or layer has been destroyed or recyled t Hello, I have a problem when the ...

  4. 一次 Redis 事务使用不当引发的生产事故

    这是悟空的第 170 篇原创文章 官网:http://www.passjava.cn 你好,我是悟空. 本文主要内容如下: 一.前言 最近项目的生产环境遇到一个奇怪的问题: 现象:每天早上客服人员在后 ...

  5. mysql优化, 删除数据后物理空间未释放(转载)

    mysql优化, 删除数据后物理空间未释放(转载) OPTIMIZE TABLE 当您的库中删除了大量的数据后,您可能会发现数据文件尺寸并没有减小.这是因为删除操作后在数据文件中留下碎片所致.OPTI ...

  6. 关于mysql 删除数据后物理空间未释放(转载)

    转自 关于mysql 删除数据后物理空间未释放(转载) - NETDATA - 博客园http://www.cnblogs.com/shawnloong/archive/2013/02/07/2908 ...

  7. jsch连接sftp后连接未释放掉问题排查

    项目中通过jsch中的sftp实现上传下载文件.在压测过程中,由于调用到sftp,下载文件不存在时,系统不断抛出异常,内存飙升,逐渐把swap区也占满,通过top监控未发现占用内存的进程,通过查找ss ...

  8. java输入输出流操作同一资源实现覆盖引发冲突的解析

    一.问题发生的场景 题目:把s.txt中大写转成小写,小写转成大写,空格转成下划线,在输入到文件中覆盖之前的 前面的没有问题,问题出现在后面的覆盖文件上,输入流.输出流要操作同一个文件的问题 二.小白 ...

  9. linux删除文件未释放空间问题处理

    linux删除文件未释放空间问题处理 或者 /根分区满了 (我的根分区是/dev/sda1,/dev/sda1满了) http://blog.csdn.net/donghustone/article/ ...

随机推荐

  1. pig的内置函数小总结(不全)

    piggybank里面有很多函数,可以用register和define调用.也可以用java仿照piggybank自行开发. 比如读sequence二进制文件,可以用piggybank里面函数Sequ ...

  2. SQL Server扫盲系列——镜像篇

    为方便查看,并以专题形式展示,所以我会把一些文章整合起来.本部分为SQL Server镜像系列: 本文出处:http://blog.csdn.net/dba_huangzj/article/detai ...

  3. VB.NET版机房收费系统---组合查询

    查询的意思就是查找,寻找,指在某一个或几个地方找出自己所要的信息,假如我想搜索一下我自己写的博客,名字叫做初雪之恋,我在百度的搜索框中输入丁国华三个字,会有怎样的惊喜等着我? 啊哦,这个信息并不是我想 ...

  4. 看uboot的时候发现随机数的另外一种算法

    #include <stdio.h> #include <time.h> static unsigned int y = 1U; unsigned int rand_r(uns ...

  5. UIScrollView&nbsp;UIPageViewControlle…

    1.UIScorollView    是ios中提供的滑动控件,用来解决当内容区域大于scorollView可视区域时,可以通过滑动的方式查看整个内容区域,UIScorollView 的滑动控件的基类 ...

  6. mybatis 配置 log4j 日志

    mybatis 配置 log4j 日志 使用Mybatis的时候,可能需要输出(主要是指sql,参数,结果)日志,查看执行的SQL语句,以便调试,查找问题. 测试Java类中需要加入代码: stati ...

  7. css文本样式-css学习之旅(4)

    color:颜色derction:方向:line-height:行高:letter-spaceing:字符间距:text-align:对齐方向:text-decoration:装饰:text-inde ...

  8. 如何搭建modem编译环境

    [DESCRIPTION] (1)MT6577以及之前的chip平台(如MT6575,73等) 的modem编译环境和MTK的Feature Phone的编译环境一样,即Windows+RVCT (2 ...

  9. java 编程性能调优

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  10. linux下挂载U盘

    转:http://www.cnblogs.com/yeahgis/archive/2012/04/05/2432779.html linux下挂载U盘 一.Linux挂载U盘: 1.插入u盘到计算机, ...