views:

139

answers:

3

I am trying to optimize my engine (C# + SlimDX) to make as less allocations as possible (to prevent the GC from firing too often) using as guide a profiler that gives me where the garbaged object are generated. Its going pretty well (going down from like 20 MB garbaged every 5s to 8 MB garbaged every 1 minute and half (yep, it was very little optimized XD)) There is a method where I can't find anything declarated and i don't know what's to do. It seems this method generate 2 garbaged object per execution in its body (not on a called function) :

Can somebody guide me to understand why this function generate object to be garbaged? I really don't have a clue.

    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();
        }
  }

Notes :

The new byte[Size] is NEVER called due to caching. The MathHelper function simply copy each element (Single) from one object to another without creating anything. The base.Update() does almost nothing (and anyway is derived from ALL object in my engine, but only here i have the garbage object)

Thanks!!!

EDIT:

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

Here's the code of the LockData(). I don't think it generates anything :|

A: 

I'm just guessing, but it looks like you're creating two SynchronizedObject objects in the bottom nine lines of that function:

SynchronizedObject so = SynchronizationEventWriter.LockData();

and

so = SynchronizationEventWriterNum.LockData();

No detailed knowledge of SynchronizedObject or whether LockData() actually creates anything, but it's the only choice I can see in your code...

Xav
I posted the code of the call, it doesn't make anything...Parent.Value is a simple property (get;set;)
feal87
+1  A: 

What's in base.Update(), anything?

Can your profiler dump the heap? If so why I'd put a breakpoint just before this method and dump the heap and then again straight afterwards. That way you'll be able to see what type of object has been created.

Short of that a brute force approach of commenting out line by line is another (horrible) idea.

Do your MathHelper methods create a temp object?

Paolo
Wait, i'll try it right away.
feal87
It says me only :System.Int32 (+1 object + 12 bytes)Does Int32 count as object? :|
feal87
Tried to use preallocated Int32, but no change happened
feal87
Hmm, no Int32 is a value type so should only be allocated on the stack (unless it is a field as part of an object on the heap).
Paolo
+1  A: 

I've resolved!!!

The problem was that the so.Synchronizedobject = PrimitivesCount; was assigning an Int32 to an Object class. It seems that this replaces every time the object causing the old object to be garbaged. I resolved by using a box class to enclose the Int32 object and simply change the value inside.

feal87