垃圾回收收集什么?

3
我正在尝试优化我的引擎(C# + SlimDX)以尽可能减少分配(以防止GC过于频繁),使用一个给出生成垃圾对象位置的分析器作为指导。进展还算不错(将每5秒产生的垃圾从20MB降至每1分30秒的8MB(是的,这很少被优化 XD))。
有一个方法我找不到任何声明,我不知道该怎么办。它似乎在其主体内部(而不是在调用的函数上)每执行一次就会生成两个垃圾对象:
有人能指导我理解为什么这个函数会生成垃圾对象吗?我真的没有线索。
    public override void Update()
    {
        base.Update();
        if (LastCheckInstancesNumber != Instances.Count)
        {
            LastCheckInstancesNumber = Instances.Count;
            _needToRegenerateUpdate = true;
        }
        // Crea byte array da usare nel prossimo draw.
        if (_needToRegenerateUpdate)
        {
            Int32 PrimitivesCount = Instances.Count;
            Int32 Size = PrimitivesCount * 80;

            if ((ByteUpdateTemp != null) && (ByteUpdateTemp.Length < Size))
                ByteUpdateTemp = new byte[Size];
            int offset = 0;

            PrimitivesCount = 0;
            Int32 Count = Instances.Count;
            for (int i = 0; i < Count; i++)
            {
                InstancedBase3DObjectInstanceValues ib = Instances[i];
                if (ib.Process)
                {
                    MathHelper.CopyMatrix(ref ib._matrix, ref MatrixTemp);
                    MathHelper.CopyVector(ref ib._diffuseColor, ref ColorTemp);

                    ObjectUpdateTemp[0] = MatrixTemp.M11;
                    ObjectUpdateTemp[1] = MatrixTemp.M12;
                    ObjectUpdateTemp[2] = MatrixTemp.M13;
                    ObjectUpdateTemp[3] = MatrixTemp.M14;
                    ObjectUpdateTemp[4] = MatrixTemp.M21;
                    ObjectUpdateTemp[5] = MatrixTemp.M22;
                    ObjectUpdateTemp[6] = MatrixTemp.M23;
                    ObjectUpdateTemp[7] = MatrixTemp.M24;
                    ObjectUpdateTemp[8] = MatrixTemp.M31;
                    ObjectUpdateTemp[9] = MatrixTemp.M32;
                    ObjectUpdateTemp[10] = MatrixTemp.M33;
                    ObjectUpdateTemp[11] = MatrixTemp.M34;
                    ObjectUpdateTemp[12] = MatrixTemp.M41;
                    ObjectUpdateTemp[13] = MatrixTemp.M42;
                    ObjectUpdateTemp[14] = MatrixTemp.M43;
                    ObjectUpdateTemp[15] = MatrixTemp.M44;
                    ObjectUpdateTemp[16] = ColorTemp.X;
                    ObjectUpdateTemp[17] = ColorTemp.Y;
                    ObjectUpdateTemp[18] = ColorTemp.Z;
                    ObjectUpdateTemp[19] = ColorTemp.W;
                    ByteConverter.WriteSingleArrayToByte(ref ObjectUpdateTemp, ref ByteUpdateTemp, offset);
                    offset += 20;

                    PrimitivesCount++;
                }
            }

            SynchronizedObject so = SynchronizationEventWriter.LockData();
            so.Synchronizedobject = ByteUpdateTemp;
            SynchronizationEventWriter.Update();
            SynchronizationEventWriter.UnlockData();
            _needToRegenerateUpdate = false;

            so = SynchronizationEventWriterNum.LockData();
            so.Synchronizedobject = PrimitivesCount;
            SynchronizationEventWriterNum.Update();
            SynchronizationEventWriterNum.UnlockData();
        }
  }

注意:

由于缓存,新的byte[Size]永远不会被调用。 MathHelper函数只是将一个对象中的每个元素(Single)复制到另一个对象中,而不创建任何内容。 base.Update()基本上什么也没做(无论如何,它都派生自我的引擎中的所有对象,但只有在这里我有垃圾对象)。

谢谢!!!

编辑:

    internal void GetLock()
    {
        Monitor.Enter(InternalLock);
        Value.Locked = true;
        Value.LockOwner = Thread.CurrentThread;
    }
    public SynchronizedObject LockData()
    {
        Parent.GetLock();
        return Parent.Value;
    }

这是 LockData() 的代码。我不认为它会生成任何东西 :|

1
只是猜测,SynchronizedObject so = SynchronizationEventWriter.LockData(); 返回一个新实例吗? - almog.ori
不要返回受监视器保护的对象的引用。 - feal87
3个回答

2

我解决了!!!

问题在于so.Synchronizedobject = PrimitivesCount; 将Int32赋值给Object类。似乎这会每次替换对象,导致旧对象被垃圾回收。

我通过使用一个包装类来封装Int32对象并简单地更改内部的值来解决了这个问题。


1

base.Update() 里面有什么东西吗?

你的分析器能够转储堆吗?如果可以,我会在这个方法之前设置一个断点并转储堆,然后再直接进行。这样你就能看到创建了什么类型的对象。

除此之外,逐行注释的暴力方法是另一个(可怕的)想法。

你的 MathHelper 方法会创建临时对象吗?


它只告诉我:System.Int32(+1个对象+12字节)Int32算作对象吗? :| - feal87
尝试使用预分配的Int32,但没有发生变化。 - feal87
嗯,Int32是值类型,因此应该只在堆栈上分配(除非它是堆上对象的字段)。 - Paolo

0
我只是猜测,但看起来你在该函数的最后九行中创建了两个SynchronizedObject对象:
SynchronizedObject so = SynchronizationEventWriter.LockData();

so = SynchronizationEventWriterNum.LockData();

我并不清楚SynchronizedObject的详细信息,也不知道LockData()是否真正创建了任何东西,但在你的代码中,这似乎是唯一的选择...


我发布了调用代码,但它没有做任何事情...Parent.Value是一个简单的属性(get;set;)。 - feal87

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接