经典的0.001秒,让程序回复正常的0.001秒。
本文出现的源头还得从DbHelper说起,先来说说这个DbHelper的演化(产生)过程:
(一)、说起DbHelper大家都非常的熟悉了,就是一个数据库操作帮助类,如果说简单的话,几个静态的方法:
1)、public static DataSet ExecNomQuery(parameters....);
2)、public static DataTable ExecNomQuery(parameters....);
3)、public static bool ExecCommand(parameters....);
4)、public static object ExecScalar(parameters....);
5)...
(二)、如果没有特殊要求的话上面4个方法基本上就够用了,但是如果涉及到事务处理等操作,上面这个数据库帮助类就会显得有点力不从心了。也是正是由于如此,自己把原来的静态数据库帮助类进行了修改,全部采用实例成员,采用new的方式来创建DbHelper,用完后采用using方式将对象Dispose掉。程序运行效果也还可以,如果不是非常高负荷的应用,这样的DbHelper基本上都可以应付。
(三)、为了不至于到处出现new DbHelper()的操作,于是就产生了创建DbHelper对象的简单工厂类。
(四)、在不断应用的过程中,需要对数据库帮助类进行扩展,于是原本只支持MSSqlServer数据库的DbHelper又开始不够用了,为了不改变太多原来DbHelper的代码,于是直接从DbHelper中抽象出一个IDbHelper接口出来,将原来的DbHelper改名为MSSqlDbHelper,同时创建了一个支持Oracle数据库的OracleDbHelper,这样就可以根据通过工厂类创建自己需要的数据库帮助类了(MSSqlServer、OracleDbHelper,如果需要的话,可以自己扩展,只需要继承IDbHelper接口即可)。
(五)、为了消除数据库帮助类中的if;else if;分支的个数,于是产生了抽象工厂类IDbHelperFactory,先通过反射创建IDbHelperFactory,然后通过工厂类创建IDbHelper。(注:抽象工厂类彻底的消除简单工厂类的if-else if分支)
(六)、后来有一段时间一头钻入Ioc的漩涡中,于是产生了一个想法,想自己写一个Ioc容器,。。。哗啦哗啦。。。经过几天的折腾,一个自己打造的精简版的Ioc容器诞生了,通过构造函数/或者setter方式注入创建IDbHelperFactory,然后创建IDbHelper对象。
(七)、上面的IDbHelper用了一段时间,感觉还不错,但是不知不觉的使用过程中,DbHelper中增加了一个又一个的字段、属性、方法(都是实例成员),导致DbHelper对象不断膨胀,从而使得DbHelper实例化的时候,对内存的开销相比最原始的静态数据库帮助类大了许多,想到自己的Ioc容器创建对象的生命周期中有一种是Pooled类型的,即组件池模式。对于这个组件池模式,在这里好好解释一下(对Ioc有一定研究的人可以飘过),组件池模式,即容器在讲对象创建完以后,同时保存一份对象的引用在自己的Pool中,这样调用方在对象调用完毕之后,GC不会将对象回收掉,因为Pool中还有一个该对象的引用。这样在下一个创建该类对象的调用中,Ioc容器就可以先在Pool中寻找是否有可用的对象,如果有的话,就直接返回Pool中的对象,否则重新创建对象。好,问题产生了:
1)、Ioc容器如何判断哪些对象已经不在使用中;
2)、调用方在什么时候释放掉从容器中获取到的对象实例。
基于以上两点,我们可以参考微软自带的数据库连接池功能,即使用的时候,将对象标记为使用中(Status=Open),使用完毕后,将数据库连接对象Close掉,以便其他地方调用。于是一个简单的接口产生了,命名为“可重用对象”:
2 {
3 bool IsOnUsing{get;set;}
4 }
该接口只有一个bool类型的状态属性:IsOnUsing,用于标记该对象是否处于使用中状态。
下面给出从对象池中获取对象的代码构架:
IList<IReusedObject > _ListInstance;
//对象池线程安全锁
object _Lock;
//对象池容量
int _Capacity;
public IocContainer()
{
this._ListInstance = new List<IReusedObject >();
this._Lock = new object();
//默认设置组件池容量为10,也可以通过其他方式来修改容量
this._Capacity = 10
}
public object GetInstance(Type t,....)
{
IReusedObject retValue;
lock(this._Lock)
{
foreach(IReusedObject obj in this._ListInstance)
{
if(!obj.IsOnUsing)
{
retValue = obj;
break;
}
}
if(retValue != null)
{
retValue.IsOnUsing = true;
return retValue;
}
//如果容器的的容量还为超过指定容量大小,则可以重新创建对象实例。
if(this._ListInstance.Count < this._Capacity)
{
//通过类型创建该类型的对象实例
//该方法由容器辅助方法完成,在这里就省略了
retValue = CreateInstance(t);
retValue.IsOnUsing = true;
this._ListInstance.Add(retValue);
return retValue;
}
//否则递归调用方法再次从容器中获取对象实例
else
{
return this.GetInstance(t,....);
}
}
}
写完上述方法后心中窃喜了一阵子,于是迫不及待的创建了30(只要大于组件池的容量即可)个线程来测,结果还没等我反应过来,就发现代码出现了死循环程序提示内存溢出了。。。。
着实让我悲剧了一阵子。。。。。。。。。。。。实在不知道为什么会出现这样的问题,难道是:
【先声明:我测试的对象就是上面的IDbHelper,DbHelper继承了IDispose和IReusedObject两个接口,并且在Dispose方法中加了“IsOnUsing = false;",所以通过using(IDbhelper dbHelper = ....){.....}的方式调用DbHelper对象使用完毕后,对象都会被对象池重用。】
1)、组件池中的所有的对象都一直被占用在。。。。。
2)、还是什么其他原因。。。。
答案已经给出:就在代码中红色标识处。
经过大家的激烈讨论,发现有一个地方可以优化的:那就是如果调用方忘记经从Ioc容器中获取的对象Dispose()掉的话,那么这个对象就是个死角,永远也不会被释放掉,直到程序退出为止。所以下一步会针对这个Ioc容器进行优化,为组件池中的组件增加对象超时时间(即对象空闲一段时间就将该对象从组件池中释放掉)。
下面贴出优化后的代码,欢迎大家指正,谢谢!
{
IReusedObject retValue = null;
DateTime now;
//累计循环次数
int count = 3;
//循环因子
int i = 0;
//先到组件池中查找可用的对象
lock (this._Lock)
{
while (true && i++ < count)
{
now = DateTime.Now;
//先从组件池中获取对象
retValue = this._ListInstance.Find(obj => !obj.IsOnUsing);
//如果能够获取到,则直接返回
if (retValue != null)
{
#if DEBUG
Common.InnerLogHelper.WriteLog("Get instance from pool by PooledIocType[Current Count = " + this.InstanceCount.ToString() + "].", "SAS.Utilities.IOC.IocType.GetInstance()");
#endif
retValue.LastVisitTime = now;
retValue.IsOnUsing = true;
break;
}
//否则,如果组件池的还没装满,则重新创建对象实例,并放入组件池中
else if (this._ListInstance.Count < this.Capacity)
{
retValue = base.CreateInstance() as IReusedObject;
if (retValue == null)
{
throw new Exception("Type[" + base.Type.FullName + "] must implement from IReusedObject interfact.");
}
else
{
#if DEBUG
Common.InnerLogHelper.WriteLog("Create a new instance by PooledIocType[Current Count = " + this.InstanceCount.ToString() + "].", "SAS.Utilities.IOC.IocType.GetInstance()");
#endif
this._ListInstance.Add(retValue);
break;
}
}
//否则移除组件池中超时的对象,然后进入下一次循环
else
{
//移除超时对象
this._ListInstance.RemoveAll(obj => obj.LastVisitTime.AddMilliseconds(obj.TimeOut) < now);
Thread.Sleep(10);
continue;
}
}
}
if (retValue == null)
{
throw new Exception("Get obj from pool timeout.");
}
return retValue;
}
ASP.NET开发技术交流群: 67511751(人员招募中...)
转载于:https://www.cnblogs.com/Juvy/archive/2011/12/12/2285403.html
经典的0.001秒,让程序回复正常的0.001秒。相关推荐
- 微信接入服务器源码,经典论坛程序Discuz! Q 1.0 发布:完全开放源码,原生接入微信...
中文 PC 互联网知名社区开源论坛系统 Discuz! 在过去 15 年间,服务过超过 200 万网站客户.其推出的 UCenter.SupeSite,ECshop 等组件所代表的产品理念对今天移动互 ...
- c语言随机延迟5-10秒,linux下写个C语言程序,要求有0.5微秒以下的延时,要怎样写...
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include #include #define B break void de(int timee) { unsi ...
- 这 10 种 MySQL 经典错误案例,99% 的程序员一定遇到过!你呢?
今天就给大家列举 MySQL 数据库中,最经典的十大错误案例,并附有处理问题的解决思路和方法,希望能给刚入行,或数据库爱好者一些帮助,今后再遇到任何报错,我们都可以很淡定地去处理.学习任何一门技术的同 ...
- Java黑皮书课后题第7章:**7.24(仿真:优惠券收集问题)优惠券收集问题是一个经典的统计问题。编写程序,模拟要得到四张不同花色的牌所需要的选取次数,然后显示选中的四张牌
**7.24(仿真:优惠券收集问题)优惠券收集问题是一个经典的统计问题.编写程序,模拟要得到四张不同花色的牌所需要的选取次数,然后显示选中的四张牌 题目 题目描述与运行示例 破题:花色与数字 代码 题 ...
- 一对经典的时间获取客户/服务器程序
前言 本文通过一对经典的时间获取客户/服务器程序,展现了Linux网络编程的大体框架,为以后更深入的学习打下基础. 客户服务器模式网络编程的大体框架 客户端代码 1 #include <stdi ...
- c语言怎么让程序停止3秒,求助!!!!用单片机的定时器T1怎么写一个LED亮2秒灭3秒的程序 C语言...
求助!!!!用单片机的定时器T1怎么写一个LED亮2秒灭3秒的程序 C语言 关注:120 答案:4 mip版 解决时间 2021-02-05 00:55 提问者習慣邇的習慣 2021-02-04 ...
- VC6.0(VC++6.0)使用教程(使用VC6.0编写C语言程序)
VC6.0(VC++6.0)使用教程(使用VC6.0编写C语言程序) Visual C++ 6.0简称VC或者VC6.0,是微软1998年推出的一款C/C++ IDE,界面友好,调试功能强大.VC6. ...
- c语言滤出是个最小值,经典滤波算法及C语言程序
<经典滤波算法及C语言程序>由会员分享,可在线阅读,更多相关<经典滤波算法及C语言程序(9页珍藏版)>请在人人文库网上搜索. 1.经典的滤波算法经典的滤波算法 可以用用可以用用 ...
- 我用纯C语言开发的中英文混合分词服务器3.0正式发布,词库190多万词,每秒切分5万+,同时提供 c、java、C#、delphi、js调用范例
我用纯C语言开发的中英文混合分词服务器3.0正式发布,词库190多万词,每秒切分5万+,同时提供 c.java.C#.delphi.js调用范例 百万商业圈中英文混合分词服务器3.0正式发布, 绝对稳 ...
最新文章
- 真正的博士是如何参加AAAI, ICML, ICLR等AI顶会的?
- ADS与RealView MDK
- ASP.NET缓存之 没有为 SQL 缓存通知启用数据库“ReplaceShop”。
- 小米开源文件管理器MiCodeFileExplorer-源码研究(3)-使用最多的工具类Util
- Moonlight已经可以下载,目前是0.6版
- mysql删除delete语句
- HDL的综合和c语言的编译区别,C语言与verilog 的区别及相互转化
- 漫步数理统计十九——独立随机变量
- html ie浏览器写入内容,js在IE下创建本地文件,并读取内容
- r430服务器如何用u盘做系统,DELL R430服务器U盘安装操作系统指南.docx
- 菲尼克斯电源模块的安装
- Moloch网络流量分析工具
- 二、概率p值检验例题(R语言)
- 雍正《连平州志·序》:揭秘连平起源之迷
- 生产者消费者模式剖析
- 看了这篇干货,再也不怕Mac内存不足了!
- 剑指Offer--约瑟夫环问题
- PL2303HX在Windows 10下面不装安装驱动的解决办法(Code:10)
- 宠辱不惊,闲看庭前花开花落
- 个人简历自我介绍竞聘PPT模板