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方法进行释放。

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


结束语

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

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

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

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

相关文章
|
2月前
|
存储 安全 算法
深入剖析JVM内存管理与对象创建原理
JVM内存管理,JVM运行时区域,直接内存,对象创建原理。
67 2
|
20天前
|
存储 缓存 算法
JVM对象创建与内存分配机制
该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
16 0
|
2月前
为对象分配内存TLAB
为对象分配内存TLAB
|
存储 缓存 Java
【JVM】8. 对象实例化及直接内存(2)
8.2.3. 对齐填充(Padding) 不是必须的,也没有特别的含义,仅仅起到占位符的作用 举例
|
2月前
|
存储 算法 安全
Come on ! Java对象内存分配与回收策略
Come on ! Java对象内存分配与回收策略
53 0
|
8月前
|
Java 测试技术
Netty4底层用对象池和不用对象池实践优化
Netty4底层用对象池和不用对象池实践优化
30 0
|
8月前
|
安全 编译器 程序员
25 C++ - 动态对象创建
25 C++ - 动态对象创建
33 0
|
12月前
|
存储 缓存 算法
jvm之对象实例化及直接内存解读
jvm之对象实例化及直接内存解读
|
存储 算法 Java
【JVM】8. 对象实例化及直接内存(1)
8.1. 对象实例化 8.1.1. 创建对象的方式 new:最常见的方式、Xxx的静态方法,XxxBuilder/XxxFactory的静态方法 Class的newInstance方法:反射的方式,只能调用空参的构造器,权限必须是public Constructor的newInstance(XXX):反射的方式,可以调用空参、带参的构造器,权限没有要求 使用clone():不调用任何的构造器,要求当前的类需要实现Cloneable接口,实现clone() 使用序列化:从文件中、从网络中获取一个对象的二进制流
|
存储 缓存 算法
<JVM上篇:内存与垃圾回收篇>08-对象实例化及直接内存
<JVM上篇:内存与垃圾回收篇>08-对象实例化及直接内存
<JVM上篇:内存与垃圾回收篇>08-对象实例化及直接内存