【问题标题】:Is it possible to modify a ReadOnlyCollection using reflection是否可以使用反射修改 ReadOnlyCollection
【发布时间】:2011-03-08 19:56:19
【问题描述】:

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

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

这些对象存储在嵌套的 ReadOnlyCollections 中,所以我现在正在尝试使用反射将其中一些集合设置为空,当我完成它们时,垃圾收集器可以收集使用的内存。

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,这似乎完成了任务,但是当我运行此代码时,内存消耗不断增加,就像我运行时一样快根本不要将类设置为 null。

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

【问题讨论】:

  • 你试过反射器来看看你的 API 到底在做什么。只读集合只是对读/写集合的引用。所以除非你能找到源头,否则它(可能)是行不通的。我假设您已经尝试过您的 SDK 供应商
  • 我一直在使用反射器查看 SDK,这就是我对私有类字段的了解。我认为如果我使包含对只读集合的​​引用的对象为空,那么 GC 将看到只读集合没有对它的引用,并且它的内部列表没有引用并清理堆起来。
  • “我现在正在尝试使用反射将其中一些集合设置为空”——几乎可以肯定是错误的/解决这个问题的最坏方法。也就是说,即使从字面上看,这个问题也太宽泛了,因为它完全取决于集合的使用方式,甚至它们到底是什么集合类。实际上,这应该是一个不同的问题,特别是关于如何处理有问题的库及其过多的内存需求。使用反射处理只读集合肯定会遇到麻烦

标签: c# reflection garbage-collection readonly-collection


【解决方案1】:

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

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

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

【讨论】:

  • 1.我尝试在逻辑上将其拆分(这是我尝试的第一件事),但根对象有很多引用,并最终抛出 TimeOutException,因为它的连接池中的连接用完了。 2. 300MB 用于单个构建。我在大约 5-6 次构建后遇到了 OOM,由于我们是一个新团队,我们的功能数量将增加 5-6 倍并非不可能。我实际上和 SDK 团队谈过,他们知道这个问题,并邀请我在他们的源代码中修复它:)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多