C# | 对象池

简介: 当我们在做软件开发时经常会需要创建很多的相同且特殊的对象,比如线程、内存、数据库连接、文件句柄等,这类特殊对象有着占用IO资源、创建或销毁的开销大等特点,会导致系统的性能下降和资源浪费。而对象池的出现就是为了解决此类问题,使用对象池来管理这些对象让它们可以被重复使用,从而提高效率。

image.png

对象池

@[toc]

前言

当我们在做软件开发时经常会需要创建很多的相同且特殊的对象,比如线程、内存、数据库连接、文件句柄等,这类特殊对象有着占用IO资源、创建或销毁的开销大等特点,会导致系统的性能下降和资源浪费。而对象池的出现就是为了解决此类问题,使用对象池来管理这些对象让它们可以被重复使用,从而提高效率。


什么是对象池

那么什么是对象池呢?
就是在一个池中预先创建n个对象,当需要使用的时候就从这个池中获取一个实例,并使用完毕后并不销毁释放,而是再将其放回池中,以便可以多次重复使用。

对象池的优点

对象池可以大幅度的减少对象创建和销毁的过程,从而提高程序的运行效率和资源的利用率。此外对象池还可以准确的控制对象创建的数量,因此对于程序的稳定性也有极大助益。

对象池的缺点

对象池的劣势在于它的机制就已经决定了对象池中会有一定数量的对象持续占用内存,如果池中保留的对象的数量过多,可能会导致系统的内存不足,也可能导致其他进程无法拿到系统资源。
还有就是对象池需要进行对象的管理和维护,对于内存池中保留的对象的个数如何取值就需要结合软件和硬件的实际情况进行综合考量了,需要在运行效率和资源消耗上取得平衡。如果管理不当可能会适得其反。


实现思路

设计对象池的思路主要是确定对象池的大小、对象的创建方式、对象的回收方式以及线程安全等问题。通常情况下,我们需要在程序初始化时创建一定数量的对象,并将这些对象存储在对象池中。
当需要使用对象时,从对象池中获取一个可用的对象,使用完毕后将其放回对象池中。如果对象池中的对象数量不足,可以根据需要动态地创建新的对象并添加到对象池中。

简单的对象池示例

下面是一个简易的对象池例子:

public class ObjectPool<T>
{
   
   
    private readonly Func<T> _objectFactory;
    private readonly ConcurrentBag<T> _objects;

    public ObjectPool(Func<T> objectFactory)
    {
   
   
        _objectFactory = objectFactory;
        _objects = new ConcurrentBag<T>();
    }

    public T GetObject()
    {
   
   
        T obj;
        if (_objects.TryTake(out obj))
        {
   
   
            return obj;
        }
        return _objectFactory();
    }

    public void PutObject(T obj)
    {
   
   
        _objects.Add(obj);
    }
}

上面的代码中使用了ConcurrentBag类来实现线程安全的对象管理。
在创建ObjectPool对象时,需要传入一个用于创建对象的委托函数。
当需要获取对象时,先尝试从对象池中获取一个可用的对象,如果对象池中没有可用的对象,则根据委托函数创建一个新的对象。使用完毕后,将对象放回对象池中。

优化:增加保留个数限制

接下来优化一下这个例子,添加一个值限制对象池中保留对象的个数,超出限制的对象会被释放掉。

public class ObjectPool<T>
{
   
   
    private readonly Func<T> _objectFactory;
    private readonly ConcurrentBag<T> _objects;
    private readonly int _maxSize;

    public ObjectPool(Func<T> objectFactory, int maxSize)
    {
   
   
        _objectFactory = objectFactory;
        _objects = new ConcurrentBag<T>();
        _maxSize = maxSize;
    }

    public T GetObject()
    {
   
   
        T obj;
        if (_objects.TryTake(out obj))
        {
   
   
            return obj;
        }
        return _objectFactory();
    }

    public void PutObject(T obj)
    {
   
   
        if (_objects.Count < _maxSize)
        {
   
   
            _objects.Add(obj);
        }
        else
        {
   
   
            IDisposable disposable = obj as IDisposable;
            if (disposable != null)
            {
   
   
                disposable.Dispose();
            }
        }
    }
}

新增了一个名为_maxSize的属性来表示对象池中最多可以保留的对象个数。在PutObject方法中,我们判断当前对象池中的对象数量是否已经达到了最大值,如果是,则释放掉超出限制的对象,否则将对象加入到对象池中。为了保证释放对象时的安全性和可靠性,我们将对象转换为IDisposable接口,如果对象实现了IDisposable接口,则调用其Dispose方法进行释放。

这样,我们就成功地为对象池添加了一个值限制,可以避免对象池中的对象数量过多导致内存溢出和性能下降的问题。当对象池中的对象数量超过限制时,我们可以选择释放对象或者将对象丢弃掉,以保证程序的稳定性和可靠性。


结束语

通过使用对象池,我们可以大幅度减少对象的创建和销毁次数,从而提高程序的运行效率和资源的利用率。同时,我们也需要考虑对象池的大小和限制等问题,以保证程序的性能和可靠性。

在未来的文章中还会介绍其他相关的池,例如线程池、内存池等,更全面地讲解池的相关知识。

如果您觉得本文对您有所帮助,欢迎点赞收藏关注。谢谢!

禁止转载声明:
本文受到版权保护,未经作者许可,严禁转载。任何机构或个人不得以任何形式将本文用于商业用途或进行二次创作、复制、转载等行为。任何未经授权使用本文所涉及的任何内容,作者保留追究法律责任的权利。如需引用本文,请务必注明出处并获得作者的明确授权,感谢您的理解与支持!

相关文章
|
6月前
|
存储 缓存 算法
JVM对象创建与内存分配机制
该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
45 0
|
7月前
为对象分配内存TLAB
为对象分配内存TLAB
|
7月前
|
Java 程序员 编译器
【C/C++析构函数 】C++中的“垃圾回收”机制_析构
【C/C++析构函数 】C++中的“垃圾回收”机制_析构
89 0
|
7月前
|
存储 算法 安全
Come on ! Java对象内存分配与回收策略
Come on ! Java对象内存分配与回收策略
76 0
|
Java C# 图形学
Unity——对象池
Unity——对象池
117 0
|
Java 测试技术
Netty4底层用对象池和不用对象池实践优化
Netty4底层用对象池和不用对象池实践优化
53 0
|
Java
强引用、软引用、弱引用、虚引用的区别?
强引用、软引用、弱引用、虚引用的区别?
87 0
|
缓存 Java 关系型数据库
强引用、软引用、弱引用、幻象引用有什么区别和使用场景
强引用、软引用、弱引用、幻象引用有什么区别和使用场景
224 1
|
缓存 监控 关系型数据库
对象池、连接池的意义
对象池就是一个在程序启动的时候先创建好若干个可以重复使用的对象。 当程序其他地方需要使用该类型对象时,不再是向系统申请创建,而是向池发出请求。 池将会从池内发配出一个对象提供使用,当程序使用完毕后,需要将对象归还给对象池做管理。
193 0
|
设计模式 安全 编译器
线程安全的单例模式:饿汉模式&懒汉模式
线程安全的单例模式:饿汉模式&懒汉模式
238 0