是否可以使用反射修改 ReadOnlyCollection

发布于 2024-10-20 16:20:44 字数 1752 浏览 1 评论 0原文

我正在处理一个 SDK,只要主连接对象在范围内,它就会保留对其创建的每个对象的引用。定期创建新的连接对象会导致其他资源问题,这不是一个选项。

为了完成我需要做的事情,我必须迭代数千个这样的对象(几乎 100,000 个),虽然我当然不会保留对这些对象的引用,但我正在使用的 SDK 中的对象模型会保留这些引用。这会消耗内存,并且非常接近导致 OutOfMemoryExceptions。

这些对象存储在嵌套的 ReadOnlyCollections 中,所以我现在尝试的是在使用完这些集合后使用反射将其中一些集合设置为 null,以便垃圾收集器可以收集已使用的内存。

foreach (Build build in builds)
{
        BinaryFileCollection numBinaries = build.GetBinaries();
        foreach (BinaryFile binary in numBinaries)
        {
            this.CoveredBlocks += binary.HitBlockCount;
            this.TotalBlocks += binary.BlockCount;
            this.CoveredArcs += binary.HitArcCount;
            this.TotalArcs += binary.ArcCount;

            if (binary.HitBlockCount > 0)
            {
                this.CoveredSourceFiles++;
            }

            this.TotalSourceFiles++;

            foreach (Class coverageClass in binary.GetClasses())
            {
                if (coverageClass.HitBlockCount > 0)
                {
                    this.CoveredClasses++;
                }

                this.TotalClasses++;

                foreach (Function function in coverageClass.GetFunctions())
                {
                    if (function.HitBlockCount > 0)
                    {
                        this.CoveredFunctions++;
                    }

                    this.TotalFunctions++;
                }
            }

            FieldInfo fi = typeof(BinaryFile).GetField("classes", BindingFlags.NonPublic | BindingFlags.Instance);
            fi.SetValue(binary, null);
    }

当我检查 numBinaries[0] 中类成员的值时,它返回 null,这似乎完成了任务,但是当我运行此代码时,内存消耗不断增加,就像我不运行时一样快完全将类设置为空。

我试图弄清楚这种方法是否存在本质上的缺陷,或者是否有另一个对象保留对我所缺少的类 ReadOnlyCollection 的引用。

I'm dealing with an SDK that keeps references to every object it creates, as long as the main connection object is in scope. Creating a new connection object periodically results in other resource issues, and is not an option.

To do what I need to do, I must iterate through thousands of these objects (almost 100,000), and while I certainly don't keep references to these objects, the object model in the SDK I'm using does. This chews through memory and is dangerously close to causing OutOfMemoryExceptions.

These objects are stored in nested ReadOnlyCollections, so what I'm trying now, is to use reflection to set some of these collections to null when I'm done with them, so the garbage collector can harvest the used memory.

foreach (Build build in builds)
{
        BinaryFileCollection numBinaries = build.GetBinaries();
        foreach (BinaryFile binary in numBinaries)
        {
            this.CoveredBlocks += binary.HitBlockCount;
            this.TotalBlocks += binary.BlockCount;
            this.CoveredArcs += binary.HitArcCount;
            this.TotalArcs += binary.ArcCount;

            if (binary.HitBlockCount > 0)
            {
                this.CoveredSourceFiles++;
            }

            this.TotalSourceFiles++;

            foreach (Class coverageClass in binary.GetClasses())
            {
                if (coverageClass.HitBlockCount > 0)
                {
                    this.CoveredClasses++;
                }

                this.TotalClasses++;

                foreach (Function function in coverageClass.GetFunctions())
                {
                    if (function.HitBlockCount > 0)
                    {
                        this.CoveredFunctions++;
                    }

                    this.TotalFunctions++;
                }
            }

            FieldInfo fi = typeof(BinaryFile).GetField("classes", BindingFlags.NonPublic | BindingFlags.Instance);
            fi.SetValue(binary, null);
    }

When I check the values of the classes member in numBinaries[0], it returns null, which seems like mission accomplished, but when I run this code the memory consumption just keeps going up and up, just as fast as when I don't set classes to null at all.

What I'm trying to figure out is whether there's something intrinsically flawed in this approach, or if there's another object keeping references to the classes ReadOnlyCollection that I'm missing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

书间行客 2024-10-27 16:20:44

我能想到几个替代方案...

  1. 逻辑上把它分开。您提到它“在连接期间”保留所有引用。你能做 10%,关闭它,打开一个新的,跳过这 10%,再拿 10%(总共 20%),等等?
  2. 我们在这里谈论的是多少内存,这个工具会是长寿的东西吗?那么如果它在几分钟内使用大量 RAM 该怎么办?你真的遇到 OOM 了吗?如果您的系统有那么多可用 RAM 供程序使用,为什么不使用它呢?您为 RAM 付费了。这让我想起 Raymond Chen 的一篇 博客文章 大约 100% CPU消耗。
  3. 如果您确实想了解是什么阻止了某些东西被垃圾收集,那么启动 SOS 并使用 !gcroot 是一个起点。

但尽管如此,如果这确实是一个问题,我会花更多时间与第 3 方 API 提供商合作 - 在某些时候他们可能会发布您想要的更新来打破这个问题 - 然后您将回到第一个方向,或者更糟糕的是,您可能会在产品中引入细微的错误。

I can think of a few alternatives...

  1. Logically split it out. You mentioned it keeps all the references "for the duration of a connection". Can you do 10%, close it, open a new one, skip that 10%, take another 10% (total 20%), etc?
  2. How much memory are we talking about here, and is this tool going to be something that is long-lived? So what if it uses a lot of RAM for a few minutes? Are you actually getting OOMs? If your system has that much available RAM for the program to use, why not use it? You paid for the RAM. This reminds me of one of Raymond Chen's blog posts about 100% CPU consumption.
  3. If you really want to see what is keeping something from getting garbage collected, firing up SOS and using !gcroot is a place to start.

But despite all of that, if this really is a problem, I would spend more time with the 3rd party API provider - at some point they may release an update you want that breaks this - and you'll be back to square one, or worse you can introduce subtle bugs in the product.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文