Esempio n. 1
0
    // Run a single test pass on the node set. Null out node references according to the given CollectStyle,
    // run a garbage collection and then verify that each node is either live or dead as we predict. Take care
    // of the order in which test runs are made against a single TestSet: e.g. running a CollectStyle.All will
    // collect all nodes, rendering further runs relatively uninteresting.
    public void Run(CollectStyle cs)
    {
        Console.WriteLine("Running test TS:{0} CS:{1} {2} entries...",
                          Enum.GetName(typeof(TableStyle), m_style),
                          Enum.GetName(typeof(CollectStyle), cs),
                          m_count);

        // Iterate over the array of nodes deciding for each whether to sever the reference (null out the
        // entry).
        for (int i = 0; i < m_count; i++)
        {
            bool sever = false;
            switch (cs)
            {
            case CollectStyle.All:
                // Sever all references.
                sever = true;
                break;

            case CollectStyle.None:
                // Don't sever any references.
                break;

            case CollectStyle.Alternate:
                // Sever every second reference (starting with the first).
                if ((i % 2) == 0)
                {
                    sever = true;
                }
                break;

            case CollectStyle.Random:
                // Sever any reference with a 50% probability.
                if (m_rng.Next(100) > 50)
                {
                    sever = true;
                }
                break;
            }

            if (sever)
            {
                m_nodes[i] = null;
            }
        }

        // Initialize a full GC and wait for all finalizers to complete (so we get an accurate picture of
        // which nodes were collected).
        GC.Collect();
        GC.WaitForPendingFinalizers();

        // Calculate our own view of which nodes should be alive or dead. Use a simple mark array for this.
        // Once the algorithm is complete a true value at a given index in the array indicates a node that
        // should still be alive, otherwise the node should have been collected.

        // Initialize the mark array. Set true for nodes we still have a strong reference to from the array
        // (these should definitely not have been collected yet). Set false for the other nodes (we assume
        // they must have been collected until we prove otherwise).
        for (int i = 0; i < m_count; i++)
        {
            m_marks[i] = m_nodes[i] != null;
        }

        // Perform multiple passes over the handles we allocated (or our recorded version of the handles at
        // least). If we find a handle with a marked (live) primary where the secondary is not yet marked then
        // go ahead and mark that secondary (dependent handles are defined to do this: primaries act as if
        // they have a strong reference to the secondary up until the point they are collected). Repeat this
        // until we manage a scan over the entire table without marking any additional nodes as live. At this
        // point the marks array should reflect which objects are still live.
        while (true)
        {
            // Assume we're not going any further nodes to mark as live.
            bool marked = false;

            // Look at each handle in turn.
            for (int i = 0; i < m_handleCount; i++)
            {
                if (m_marks[m_handles[i].m_primary])
                {
                    // Primary is live.
                    if (!m_marks[m_handles[i].m_secondary])
                    {
                        // Secondary wasn't marked as live yet. Do so and remember that we marked at least
                        // node as live this pass (so we need to loop again since this secondary could be the
                        // same as a primary earlier in the table).
                        m_marks[m_handles[i].m_secondary] = true;
                        marked = true;
                    }
                }
            }

            // Terminate the loop if we scanned the entire table without marking any additional nodes as live
            // (since additional scans can't make any difference).
            if (!marked)
            {
                break;
            }
        }

        // Validate our view of node liveness (m_marks) correspond to reality (m_nodes and m_collected).
        for (int i = 0; i < m_count; i++)
        {
            // Catch nodes which still have strong references but have collected anyway. This is stricly a
            // subset of the next test but it would be a very interesting bug to call out.
            if (m_nodes[i] != null && m_collected[i])
            {
                Error(String.Format("Node {0} was collected while it still had a strong root", i));
            }

            // Catch nodes which we compute as alive but have been collected.
            if (m_marks[i] && m_collected[i])
            {
                Error(String.Format("Node {0} was collected while it was still reachable", i));
            }

            // Catch nodes which we compute as dead but haven't been collected.
            if (!m_marks[i] && !m_collected[i])
            {
                Error(String.Format("Node {0} wasn't collected even though it was unreachable", i));
            }
        }
    }
Esempio n. 2
0
    // Run a single test pass on the node set. Null out node references according to the given CollectStyle,
    // run a garbage collection and then verify that each node is either live or dead as we predict. Take care
    // of the order in which test runs are made against a single TestSet: e.g. running a CollectStyle.All will
    // collect all nodes, rendering further runs relatively uninteresting.
    public void Run(CollectStyle cs)
    {
        Console.WriteLine("Running test TS:{0} CS:{1} {2} entries...",
                          Enum.GetName(typeof(TableStyle), m_style),
                          Enum.GetName(typeof(CollectStyle), cs),
                          m_count);

        // Iterate over the array of nodes deciding for each whether to sever the reference (null out the
        // entry).
        for (int i = 0; i < m_count; i++)
        {
            bool sever = false;
            switch (cs)
            {
            case CollectStyle.All:
                // Sever all references.
                sever = true;
                break;

            case CollectStyle.None:
                // Don't sever any references.
                break;

            case CollectStyle.Alternate:
                // Sever every second reference (starting with the first).
                if ((i % 2) == 0)
                    sever = true;
                break;

            case CollectStyle.Random:
                // Sever any reference with a 50% probability.
                if (m_rng.Next(100) > 50)
                    sever = true;
                break;
            }

            if (sever)
                m_nodes[i] = null;
        }

        // Initialize a full GC and wait for all finalizers to complete (so we get an accurate picture of
        // which nodes were collected).
        GC.Collect();
        GC.WaitForPendingFinalizers();

        // Calculate our own view of which nodes should be alive or dead. Use a simple mark array for this.
        // Once the algorithm is complete a true value at a given index in the array indicates a node that
        // should still be alive, otherwise the node should have been collected.

        // Initialize the mark array. Set true for nodes we still have a strong reference to from the array
        // (these should definitely not have been collected yet). Set false for the other nodes (we assume
        // they must have been collected until we prove otherwise).
        for (int i = 0; i < m_count; i++)
            m_marks[i] = m_nodes[i] != null;

        // Perform multiple passes over the handles we allocated (or our recorded version of the handles at
        // least). If we find a handle with a marked (live) primary where the secondary is not yet marked then
        // go ahead and mark that secondary (dependent handles are defined to do this: primaries act as if
        // they have a strong reference to the secondary up until the point they are collected). Repeat this
        // until we manage a scan over the entire table without marking any additional nodes as live. At this
        // point the marks array should reflect which objects are still live.
        while (true)
        {
            // Assume we're not going any further nodes to mark as live.
            bool marked = false;

            // Look at each handle in turn.
            for (int i = 0; i < m_handleCount; i++)

                if (m_marks[m_handles[i].m_primary])
                {
                    // Primary is live.
                    if (!m_marks[m_handles[i].m_secondary])
                    {
                        // Secondary wasn't marked as live yet. Do so and remember that we marked at least
                        // node as live this pass (so we need to loop again since this secondary could be the
                        // same as a primary earlier in the table).
                        m_marks[m_handles[i].m_secondary] = true;
                        marked = true;
                    }
                }

            // Terminate the loop if we scanned the entire table without marking any additional nodes as live
            // (since additional scans can't make any difference).
            if (!marked)
                break;
        }

        // Validate our view of node liveness (m_marks) correspond to reality (m_nodes and m_collected).
        for (int i = 0; i < m_count; i++)
        {
            // Catch nodes which still have strong references but have collected anyway. This is stricly a
            // subset of the next test but it would be a very interesting bug to call out.
            if (m_nodes[i] != null && m_collected[i])
                Error(String.Format("Node {0} was collected while it still had a strong root", i));

            // Catch nodes which we compute as alive but have been collected.
            if (m_marks[i] && m_collected[i])
                Error(String.Format("Node {0} was collected while it was still reachable", i));

            // Catch nodes which we compute as dead but haven't been collected.
            if (!m_marks[i] && !m_collected[i])
                Error(String.Format("Node {0} wasn't collected even though it was unreachable", i));
        }
    }