Esempio n. 1
0
        /// <summary>
        /// Enumerates GCRoots of a given object.  Similar to !gcroot.
        /// </summary>
        /// <param name="target">The target object to search for GC rooting.</param>
        /// <param name="unique">Whether to only return fully unique paths.</param>
        /// <param name="cancelToken">A cancellation token to stop enumeration.</param>
        /// <returns>An enumeration of all GC roots found for target.</returns>
        public IEnumerable <RootPath> EnumerateGCRoots(ulong target, bool unique, CancellationToken cancelToken)
        {
            _heap.BuildDependentHandleMap(cancelToken);
            long totalObjects       = _heap.TotalObjects;
            long lastObjectReported = 0;

            bool parallel = AllowParallelSearch && IsFullyCached && _maxTasks > 0;

            Task <Tuple <LinkedList <ClrObject>, ClrRoot> >[] tasks;
            ObjectSet processedObjects;
            Dictionary <ulong, LinkedListNode <ClrObject> > knownEndPoints = new Dictionary <ulong, LinkedListNode <ClrObject> >();

            if (parallel)
            {
                processedObjects = new ParallelObjectSet(_heap);
            }

            else
            {
                processedObjects = new ObjectSet(_heap);
            }

            int initial = 0;

            tasks = new Task <Tuple <LinkedList <ClrObject>, ClrRoot> > [_maxTasks];

            foreach (ClrHandle handle in _heap.EnumerateStrongHandles())
            {
                Debug.Assert(handle.HandleType != HandleType.Dependent);
                Debug.Assert(handle.Object != 0);

                if (processedObjects.Contains(handle.Object))
                {
                    continue;
                }

                Debug.Assert(_heap.GetObjectType(handle.Object) == handle.Type);

                if (parallel)
                {
                    var task = PathToParallel(processedObjects, knownEndPoints, handle, target, unique, cancelToken);
                    if (initial < tasks.Length)
                    {
                        tasks[initial++] = task;
                    }
                    else
                    {
                        int i         = Task.WaitAny(tasks);
                        var completed = tasks[i];
                        tasks[i] = task;

                        if (completed.Result.Item1 != null)
                        {
                            yield return new RootPath()
                                   {
                                       Root = completed.Result.Item2, Path = completed.Result.Item1.ToArray()
                                   }
                        }
                        ;
                    }
                }
                else
                {
                    var path = PathTo(processedObjects, knownEndPoints, new ClrObject(handle.Object, handle.Type), target, unique, false, cancelToken).FirstOrDefault();
                    if (path != null)
                    {
                        yield return new RootPath()
                               {
                                   Root = GetHandleRoot(handle), Path = path.ToArray()
                               }
                    }
                    ;
                }

                ReportObjectCount(processedObjects.Count, ref lastObjectReported, totalObjects);
            }

            foreach (ClrRoot root in _heap.EnumerateStackRoots())
            {
                if (!processedObjects.Contains(root.Object))
                {
                    Debug.Assert(_heap.GetObjectType(root.Object) == root.Type);

                    if (parallel)
                    {
                        var task = PathToParallel(processedObjects, knownEndPoints, root, target, unique, cancelToken);

                        if (initial < tasks.Length)
                        {
                            tasks[initial++] = task;
                        }
                        else
                        {
                            int i         = Task.WaitAny(tasks);
                            var completed = tasks[i];
                            tasks[i] = task;

                            if (completed.Result.Item1 != null)
                            {
                                yield return new RootPath()
                                       {
                                           Root = completed.Result.Item2, Path = completed.Result.Item1.ToArray()
                                       }
                            }
                            ;
                        }
                    }
                    else
                    {
                        var path = PathTo(processedObjects, knownEndPoints, new ClrObject(root.Object, root.Type), target, unique, false, cancelToken).FirstOrDefault();
                        if (path != null)
                        {
                            yield return new RootPath()
                                   {
                                       Root = root, Path = path.ToArray()
                                   }
                        }
                        ;
                    }

                    ReportObjectCount(processedObjects.Count, ref lastObjectReported, totalObjects);
                }
            }

            foreach (Tuple <LinkedList <ClrObject>, ClrRoot> result in WhenEach(tasks))
            {
                ReportObjectCount(processedObjects.Count, ref lastObjectReported, totalObjects);
                yield return(new RootPath()
                {
                    Root = result.Item2, Path = result.Item1.ToArray()
                });
            }

            ReportObjectCount(totalObjects, ref lastObjectReported, totalObjects);
        }