为什么 Roslyn 中有这么多对象池的实现?

2024-05-13

The 对象池 http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/ObjectPool%25601.cs,20b9a041fb2d5b00是 Roslyn C# 编译器中使用的一种类型,用于重用经常使用的对象,这些对象通常会经常更新和垃圾收集。这减少了必须发生的垃圾收集操作的数量和大小。

Roslyn 编译器似乎有几个独立的对象池,每个池都有不同的大小。我想知道为什么有这么多实现、首选实现是什么以及为什么他们选择 20、100 或 128 的池大小。

1 - 共享池 http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.Workspaces/Utilities/ObjectPools/SharedPools.cs,b2114905209e7df3- 存储 20 个对象的池,如果使用 BigDefault,则存储 100 个对象。这个也很奇怪,因为它创建了一个新的 PooledObject 实例,当我们尝试池化对象而不是创建和销毁新对象时,这是没有意义的。

// Example 1 - In a using statement, so the object gets freed at the end.
using (PooledObject<Foo> pooledObject = SharedPools.Default<List<Foo>>().GetPooledObject())
{
    // Do something with pooledObject.Object
}

// Example 2 - No using statement so you need to be sure no exceptions are not thrown.
List<Foo> list = SharedPools.Default<List<Foo>>().AllocateAndClear();
// Do something with list
SharedPools.Default<List<Foo>>().Free(list);

// Example 3 - I have also seen this variation of the above pattern, which ends up the same as Example 1, except Example 1 seems to create a new instance of the IDisposable [PooledObject<T>][3] object. This is probably the preferred option if you want fewer GC's.
List<Foo> list = SharedPools.Default<List<Foo>>().AllocateAndClear();
try
{
    // Do something with list
}
finally
{
    SharedPools.Default<List<Foo>>().Free(list);
}

2 - ListPool http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.Workspaces/Formatting/ListPool.cs,1086fa28bcfcb8ca and 字符串生成器池 http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.Workspaces/Formatting/StringBuilderPool.cs,039ef0c630df07c3- 不是严格独立的实现,而是上面所示的 SharedPools 实现的包装器,专门用于 List 和 StringBuilder。因此,这会重新使用 SharedPools 中存储的对象池。

// Example 1 - No using statement so you need to be sure no exceptions are thrown.
StringBuilder stringBuilder= StringBuilderPool.Allocate();
// Do something with stringBuilder
StringBuilderPool.Free(stringBuilder);

// Example 2 - Safer version of Example 1.
StringBuilder stringBuilder= StringBuilderPool.Allocate();
try
{
    // Do something with stringBuilder
}
finally
{
    StringBuilderPool.Free(stringBuilder);
}

3 - 混合词典 http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/PooledDictionary.cs,ebb1ac303c777646 and 池化哈希集 http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/PooledHashSet.cs,afe982be5207ab5e- 它们直接使用 ObjectPool 并具有完全独立的对象池。存储 128 个对象的池。

// Example 1
PooledHashSet<Foo> hashSet = PooledHashSet<Foo>.GetInstance()
// Do something with hashSet.
hashSet.Free();

// Example 2 - Safer version of Example 1.
PooledHashSet<Foo> hashSet = PooledHashSet<Foo>.GetInstance()
try
{
    // Do something with hashSet.
}
finally
{
    hashSet.Free();
}

Update

.NET Core 中有新的对象池实现。请参阅我的回答C# 对象池模式实现 https://stackoverflow.com/questions/2510975/c-sharp-object-pooling-pattern-implementation/30664859#30664859问题。


我是罗斯林表演 v 团队的负责人。所有对象池都旨在降低分配率,从而降低垃圾收集的频率。这是以添加长寿命(第 2 代)对象为代价的。这对编译器吞吐量略有帮助,但主要影响是使用 VB 或 C# IntelliSense 时的 Visual Studio 响应能力。

为什么有这么多的实现”。

没有快速的答案,但我可以想到三个原因:

  1. 每个实现的目的都略有不同,并且它们都针对该目的进行了调整。
  2. “分层”- 所有池都是内部的,来自编译器层的内部详细信息可能不会从工作区层引用,反之亦然。我们确实通过链接文件进行了一些代码共享,但我们尽力将其保持在最低限度。
  3. 没有付出巨大的努力来统一您今天看到的实现。

首选的实现是什么

ObjectPool<T>是首选实现,也是大多数代码使用的实现。注意ObjectPool<T>被使用ArrayBuilder<T>.GetInstance()这可能是 Roslyn 中池化对象的最大用户。因为ObjectPool<T>使用如此频繁,这是我们通过链接文件跨层复制代码的情况之一。ObjectPool<T>已调整为最大吞吐量。

在工作区层,你会看到SharedPool<T>尝试跨不相交的组件共享池实例以减少总体内存使用量。我们试图避免让每个组件创建自己的专用于特定目的的池,而是根据元素的类型进行共享。一个很好的例子是StringBuilderPool.

为什么他们选择 20、100 或 128 的池大小。

通常,这是在典型工作负载下进行分析和检测的结果。我们通常必须在分配率(池中的“未命中”)和池中的总活动字节数之间取得平衡。起作用的两个因素是:

  1. 最大并行度(访问池的并发线程)
  2. 访问模式包括重叠分配和嵌套分配。

总体而言,与编译的总实时内存(第 2 代堆的大小)相比,池中对象所持有的内存非常小,但是我们也注意不要返回巨型对象(通常是大对象)集合)回到池中 - 我们只需将它们放在地板上并调用ForgetTrackedObject

对于未来,我认为我们可以改进的一个领域是拥有长度受限的字节数组(缓冲区)池。这尤其有助于编译器发出阶段 (PEWriter) 中的 MemoryStream 实现。这些 MemoryStream 需要连续的字节数组才能快速写入,但它们的大小是动态调整的。这意味着它们偶尔需要调整大小 - 通常每次都会增大一倍。每次调整大小都是一次新的分配,但如果能够从专用池中获取调整大小的缓冲区并将较小的缓冲区返回到不同的池,那就太好了。例如,您将有一个用于 64 字节缓冲区的池,另一个用于 128 字节缓冲区的池,依此类推。总池内存将受到限制,但您可以避免随着缓冲区的增长而“搅动”GC 堆。

再次感谢您的提问。

保罗·哈林顿.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 Roslyn 中有这么多对象池的实现? 的相关文章

随机推荐

  • DI:IDisposable 对象的处理寿命

    所以我正在开发我的 DI IoC 容器OpenNETCF IoC http ioc codeplex com我有一个 合理的 功能请求 为容器集合中的 IDisposable 项目添加某种形式的生命周期管理 我目前的想法是 由于我无法查询对
  • 如何实现 Azure Functions 的自定义绑定?

    Azure Functions 附带一组固定的预先存在的绑定 同时 Azure Functions基于Web Jobs SDK 具有一些可扩展性故事 https github com Azure azure webjobs sdk exte
  • Google javascript 登录 api:无法离线访问

    我正在尝试为服务器端应用程序实现 Google 登录 如 Google 文档中所示 服务器端应用程序的 Google 登录 https developers google com identity sign in web server si
  • Google Cloud / Firebase Functions,处理每个函数的依赖关系

    我们有几个需要大量依赖项才能工作的函数 我们有所谓的 jar npm lib 地狱正在发生 并且希望限制对函数的依赖 而不是项目级别的依赖 这可能吗 编辑 尝试按照 Doug 的指示重新表述问题 我们正在使用 Firebase 函数 并且希
  • EF - 从自动迁移转向手动迁移

    结束了漫长的一天测试各种场景 我不必重新创建生产数据库 我们从 EF 开始 在开发过程中没有足够明智地从自动迁移转向命名迁移 现在 我正在尝试倒带时钟 并创建与生产数据库一致的初始迁移 是否可以将模型与迁移表中的自动迁移进行对齐 我应该创建
  • 谷歌应用程序引擎nodejs本地开发

    有没有办法在本地运行我的nodejs应用程序 以便我可以模拟在生产App Engine中运行的应用程序而无需部署它 由于某种原因 我的应用程序在 Google App Engine 中的行为与我的本地主机不同 我厌倦了每次为了查看是否存在错
  • Zend Framework 2 在视图中显示视图

    我有两个模块管理和登录 我想在管理视图 index html 中显示登录视图 login phtml 我在管理模块indexAction控制器中有以下内容 public function indexAction login new Logi
  • Zend 框架 PDF 问题

    又是我 伙计们 我有一个小问题 Create new PDF pdf new Zend Pdf Add new page to the document page pdf gt newPage Zend Pdf Page SIZE A4 p
  • 如何使用对象标记上传到 AWS S3

    有没有办法使用标签将文件上传到AWS S3 不将标签添加到S3中的现有文件 对象 我需要让该文件与我的 Tags 一起出现在 S3 中 即在单个 API 调用中 我需要这个 因为我使用 Lambda 函数 使用这些 S3 对象标签 由 S3
  • ELEMENT.style.color 在 IE 中不起作用

    在一个小型 Web 应用程序中 我使用 JavaScript 在文本框中设置一些文本及其颜色 在下面的片段中 el 是我的对象 这段代码在 Firefox Opera 和 Safari 下产生了正确的效果 但在 IE 下却没有这样的运气 我
  • C++ 计算经过的时间

    我需要计算我的函数所花费的时间 现在我正在使用 std clock 据我了解 这是测量 CPU 时间 这可能与实时不同 std clock t start double duration start std clock someFuncti
  • webrtc - 获取网络摄像头的宽高比

    我正在尝试学习如何开发 webRTC 应用程序 我想知道是否可以获得相机的宽高比 我不知道它是否有帮助 但我正在使用 webrtc io 但是 if更好 我可以停止使用它 From MDN https developer mozilla o
  • 使用 X11 窗口的 R 脚本仅打开一秒钟

    我正在通过 Linux Mint 16 命令行运行 R 脚本 它包含我想在窗口中显示的箱线图 所以我使用 x11 函数来创建该窗口 这是我的代码 testdata lt data frame sample 1 1000 size 100 r
  • 尝试将 webpack-dev-server 上的端口更改为 80 会出现错误

    我的 json 包中有这个 webpack dev server config config webpack config js port 80 我还尝试将端口添加到配置中 如下所示 devServer historyApiFallback
  • 简单的 Django 图像上传 - 图像文件不保存

    是的 我正在学习如何制作一个简单的图像上传表单以将图像上传到 MEDIA ROOT 表单呈现良好 我没有收到任何错误 但该文件未显示在 MEDIA ROOT 目录中 如果遵循文档示例但无法使其工作 我知道这是因为我没有正确理解 django
  • 如何在 Xamarin 中使用 Log4Net

    我有一个使用 Xamarin MonoTouch 的应用程序 我想在其中使用日志记录框架 搜索时我遇到了 Log4Net http logging apache org log4net http logging apache org log
  • 在 Eclipse 插件中:如何以编程方式突出显示 java 编辑器中的代码行?

    我正在尝试开发一个 eclipse 插件 它对 java 代码进行一些文档检查 并在编辑器中突出显示一些代码行 为了实现我的目标 我不想在 eclipse 中创建新的编辑器 我只是想扩展默认的 java 编辑器以在不满足某些预定要求的方法下
  • 模拟 BlazeClientBuilder[IO] 以返回模拟客户端[IO]

    我正在使用BlazeClientBuilder IO resource方法得到Client IO 现在 我想模拟客户端进行单元测试 但不知道该怎么做 有没有一个好的方法来嘲笑这个 我会怎么做 class ExternalCall val r
  • Java:等于和==

    让我们看看我们有 2 个对用户定义类实例的引用 即 Java 中的 a 和 b 会不会有一种情况 a b 但 a equals b 返回 false 当然 实施 equals 完全取决于班级 所以我可以写 class Foo public
  • 为什么 Roslyn 中有这么多对象池的实现?

    The 对象池 http source roslyn codeplex com Microsoft CodeAnalysis ObjectPool 25601 cs 20b9a041fb2d5b00是 Roslyn C 编译器中使用的一种类