Esempio n. 1
0
        private static void PrintDiagnosticInfo(DataTarget dt, ClrRuntime runtime, ClrHeap heap)
        {
            Console.WriteLine("DataTarget Info:");
            Console.WriteLine("  ClrVersions: " + String.Join(", ", dt.ClrVersions));
            Console.WriteLine("  IsMinidump: " + dt.IsMinidump);
            Console.WriteLine("  Architecture: " + dt.Architecture);
            Console.WriteLine("  PointerSize: " + dt.PointerSize);
            Console.WriteLine("  SymbolPath: " + dt.GetSymbolPath());

            Console.WriteLine("ClrRuntime Info:");
            Console.WriteLine("  ServerGC: " + runtime.ServerGC);
            Console.WriteLine("  HeapCount: " + runtime.HeapCount);
            Console.WriteLine("  Thread Count: " + runtime.Threads.Count);

            Console.WriteLine("ClrRuntime Modules:");
            foreach (var module in runtime.EnumerateModules())
            {
                Console.WriteLine("  {0,26} Id:{1}, {2,10:N0} bytes @ 0x{3:X8}",
                                  Path.GetFileName(module.FileName), module.AssemblyId, module.Size, module.ImageBase);
            }

            Console.WriteLine("ClrHeap Info:");
            Console.WriteLine("  TotalHeapSize: " + heap.TotalHeapSize);
            Console.WriteLine("  Segments: " + heap.Segments.Count);
            Console.WriteLine("  Gen0 Size: " + heap.GetSizeByGen(0));
            Console.WriteLine("  Gen1 Size: " + heap.GetSizeByGen(1));
            Console.WriteLine("  Gen2 Size: " + heap.GetSizeByGen(2));
            Console.WriteLine("  Gen3 Size: " + heap.GetSizeByGen(3));
        }
Esempio n. 2
0
        public StopwatchInfo?GetStopwatchInfo()
        {
            foreach (var runtimeModule in _runtime.EnumerateModules())
            {
                var clrType = runtimeModule.GetTypeByName("System.Diagnostics.Stopwatch");
                if (clrType == null)
                {
                    continue;
                }

                var tickFrequencyStaticField    = clrType.GetStaticFieldByName("tickFrequency");
                var isHighResolutionStaticField = clrType.GetStaticFieldByName("IsHighResolution");

                foreach (var appDomain in _runtime.AppDomains)
                {
                    var isTickFrequencyInitialized  = tickFrequencyStaticField !.IsInitialized(appDomain);
                    var isHighResolutionInitialized = isHighResolutionStaticField !.IsInitialized(appDomain);

                    if (isTickFrequencyInitialized && isHighResolutionInitialized)
                    {
                        var tickFrequency    = tickFrequencyStaticField.Read <double>(appDomain);
                        var isHighResolution = isHighResolutionStaticField.Read <bool>(appDomain);

                        return(new StopwatchInfo(tickFrequency, isHighResolution));
                    }
                }
            }

            return(null);
        }
Esempio n. 3
0
        public void StaticValueAppDomainTests()
        {
            using DataTarget dt      = TestTargets.AppDomains.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            ClrModule[] sharedModules = runtime.EnumerateModules().Where(m => Path.GetFileName(m.FileName).Equals("sharedlibrary.dll", StringComparison.OrdinalIgnoreCase)).ToArray();

            Assert.Equal(2, sharedModules.Length);
            Assert.NotEqual(sharedModules[0].AppDomain, sharedModules[1].AppDomain);

            ClrType staticType1 = sharedModules[0].GetTypeByName("SharedStaticTest");
            ClrType staticType2 = sharedModules[1].GetTypeByName("SharedStaticTest");

            Assert.NotNull(staticType1);
            Assert.NotNull(staticType2);
            Assert.NotEqual(staticType1, staticType2);

            int value2  = staticType1.StaticFields.Single().Read <int>();
            int value42 = staticType2.StaticFields.Single().Read <int>();

            if (value2 > value42)
            {
                int tmp = value2;
                value2  = value42;
                value42 = tmp;
            }

            Assert.Equal(2, value2);
            Assert.Equal(42, value42);
        }
Esempio n. 4
0
        private void TouchOtherRegions(DumpReaderLogger readerLogger, ClrRuntime runtime)
        {
            // Touch all threads, stacks, frames
            foreach (var t in runtime.Threads)
            {
                foreach (var f in t.StackTrace)
                {
                    try { f.GetFileAndLineNumber(); }
                    catch (Exception) { }
                }
            }

            // Touch all modules
            runtime.EnumerateModules().Count();

            // Touch all heap regions, roots, types
            var heap = runtime.GetHeap();

            heap.EnumerateRoots(enumerateStatics: false).Count();
            heap.EnumerateTypes().Count();

            // TODO Check if it's faster to construct sorted inside ReaderWrapper
            foreach (var kvp in readerLogger.Ranges)
            {
                _otherClrRegions.Add(kvp.Key, kvp.Value);
            }
        }
        public static IEnumerable <(ClrStaticField Field, ClrObject Object)> EnumerateAllStaticVariables(this ClrRuntime runtime)
        {
            if (runtime is null)
            {
                throw new ArgumentNullException(nameof(runtime));
            }

            foreach (ClrModule module in runtime.EnumerateModules())
            {
                foreach ((ulong mt, int _) in module.EnumerateTypeDefToMethodTableMap())
                {
                    ClrType?type = runtime.GetTypeByMethodTable(mt);

                    if (type is null)
                    {
                        continue;
                    }

                    foreach (ClrStaticField field in type.StaticFields)
                    {
                        if (field.IsObjectReference)
                        {
                            foreach (ClrAppDomain domain in runtime.AppDomains)
                            {
                                ClrObject obj = field.ReadObject(domain);
                                if (obj.IsValid && !obj.IsNull)
                                {
                                    yield return(field, obj);
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 6
0
        public void MethodHandleMultiDomainTests()
        {
            ulong[] methodDescs;
            using (DataTarget dt = TestTargets.AppDomains.LoadFullDump())
            {
                using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

                ClrType[] types = runtime.EnumerateModules().Where(m => m.Name.EndsWith("sharedlibrary.dll", System.StringComparison.OrdinalIgnoreCase)).Select(m => m.GetTypeByName("Foo")).Where(t => t != null).ToArray();

                Assert.Equal(2, types.Length);
                methodDescs = types.Select(t => t.Methods.Single(m => m.Name == "Bar")).Select(m => m.MethodDesc).ToArray();

                Assert.Equal(2, methodDescs.Length);
            }

            using (DataTarget dt = TestTargets.AppDomains.LoadFullDump())
            {
                using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();
                ClrMethod method = runtime.GetMethodByHandle(methodDescs[0]);

                Assert.NotNull(method);
                Assert.Equal("Bar", method.Name);
                Assert.Equal("Foo", method.Type.Name);
            }

            using (DataTarget dt = TestTargets.AppDomains.LoadFullDump())
            {
                using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();
                ClrMethod method = runtime.GetMethodByHandle(methodDescs[1]);

                Assert.NotNull(method);
                Assert.Equal("Bar", method.Name);
                Assert.Equal("Foo", method.Type.Name);
            }
        }
Esempio n. 7
0
 /// <summary>
 /// Note: https://github.com/microsoft/clrmd/issues/567#issuecomment-601314348
 /// </summary>
 /// <param name="runtime"></param>
 /// <param name="predicate"></param>
 /// <returns></returns>
 public static IEnumerable <ClrType> GetConstructedTypeDefinitions(this ClrRuntime runtime,
                                                                   Func <ClrType, bool> predicate)
 {
     return(runtime.EnumerateModules()
            .SelectMany(m => m.EnumerateTypeDefToMethodTableMap())
            .Select(t => runtime.GetTypeByMethodTable(t.MethodTable))
            .Where(predicate));
 }
        private MetadataRegion FindRegion(ulong address)
        {
            if (!_regionInitialized)
            {
                // Need to set this before enumerating the runtimes to prevent reentrancy
                _regionInitialized = true;

                var runtimes = RuntimeService.EnumerateRuntimes();
                if (runtimes.Any())
                {
                    foreach (IRuntime runtime in runtimes)
                    {
                        Trace.TraceInformation($"FindRegion: initializing regions for runtime #{runtime.Id}");
                        ClrRuntime clrRuntime = runtime.Services.GetService <ClrRuntime>();
                        if (clrRuntime != null)
                        {
                            Trace.TraceInformation($"FindRegion: initializing regions for CLR runtime #{runtime.Id}");
                            _regions = clrRuntime.EnumerateModules()
                                       .Where((module) => module.MetadataAddress != 0 && module.IsPEFile && !module.IsDynamic)
                                       .Select((module) => new MetadataRegion(this, module))
                                       .ToImmutableArray()
                                       .Sort();
                        }
                    }
                }
                else
                {
                    // If there are no runtimes, try again next time around
                    _regionInitialized = false;
                }
            }

            if (_regions != null)
            {
                int min = 0, max = _regions.Length - 1;
                while (min <= max)
                {
                    int            mid    = (min + max) / 2;
                    MetadataRegion region = _regions[mid];

                    if (address >= region.StartAddress && address < region.EndAddress)
                    {
                        return(region);
                    }

                    if (region.StartAddress < address)
                    {
                        min = mid + 1;
                    }
                    else
                    {
                        max = mid - 1;
                    }
                }
            }

            return(null);
        }
Esempio n. 9
0
        public void ModuleEqualityTest()
        {
            using DataTarget dt      = TestTargets.Types.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            ClrModule[] oldModules = runtime.EnumerateModules().ToArray();
            Assert.NotEmpty(oldModules);

            runtime.FlushCachedData();

            ClrModule[] newModules = runtime.EnumerateModules().ToArray();
            Assert.Equal(oldModules.Length, newModules.Length);

            for (int i = 0; i < newModules.Length; i++)
            {
                Assert.Equal(oldModules[i], newModules[i]);
                Assert.NotSame(oldModules[i], newModules[i]);
            }
        }
Esempio n. 10
0
        public void TestModuleSize()
        {
            using DataTarget dt      = TestTargets.Types.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            foreach (ClrModule module in runtime.EnumerateModules())
            {
                Assert.True(module.IsDynamic || module.Size > 0);
            }
        }
Esempio n. 11
0
        public void TestModulesNames()
        {
            using DataTarget dt      = TestTargets.Types.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            foreach (ClrModule module in runtime.EnumerateModules())
            {
                Assert.True(File.Exists(module.Name));
                Assert.True(File.Exists(module.AssemblyName));
            }
        }
Esempio n. 12
0
        private void PrintRuntimeDiagnosticInfo(DataTarget dataTarget, ClrRuntime runtime)
        {
            logger?.WriteLine(LogKind.Header, "\nRuntime Diagnostic Information");
            logger?.WriteLine(LogKind.Header, "------------------------------");

            logger?.WriteLine(LogKind.Header, "\nDataTarget Info:");
            logger?.WriteLine(LogKind.Info, string.Format("  ClrVersion{0}: {1}", dataTarget.ClrVersions.Count > 1 ? "s" : "", string.Join(", ", dataTarget.ClrVersions)));
            logger?.WriteLine(LogKind.Info, "  Architecture: " + dataTarget.Architecture);
            logger?.WriteLine(LogKind.Info, string.Format("  PointerSize: {0} ({1}-bit)", dataTarget.PointerSize, dataTarget.PointerSize == 8 ? 64 : 32));
            logger?.WriteLine(LogKind.Info, "  SymbolPath: " + dataTarget.GetSymbolPath());

            logger?.WriteLine(LogKind.Header, "\nClrRuntime Info:");
            logger?.WriteLine(LogKind.Info, "  ServerGC: " + runtime.ServerGC);
            logger?.WriteLine(LogKind.Info, "  HeapCount: " + runtime.HeapCount);
            logger?.WriteLine(LogKind.Info, "  Thread Count: " + runtime.Threads.Count);

            logger?.WriteLine(LogKind.Header, "\nClrRuntime Modules:");
            foreach (var module in runtime.EnumerateModules())
            {
                logger?.WriteLine(LogKind.Info,
                                  string.Format(
                                      "  {0,36} Id:{1} - {2,10:N0} bytes @ 0x{3:X16}",
                                      Path.GetFileName(module.FileName),
                                      module.AssemblyId.ToString().PadRight(10),
                                      module.Size,
                                      module.ImageBase));
            }

            ClrHeap heap = runtime.GetHeap();

            logger?.WriteLine(LogKind.Header, "\nClrHeap Info:");
            logger?.WriteLine(LogKind.Info, string.Format("  TotalHeapSize: {0:N0} bytes ({1:N2} MB)", heap.TotalHeapSize, heap.TotalHeapSize / 1024.0 / 1024.0));
            logger?.WriteLine(LogKind.Info, string.Format("  Gen0: {0,10:N0} bytes", heap.GetSizeByGen(0)));
            logger?.WriteLine(LogKind.Info, string.Format("  Gen1: {0,10:N0} bytes", heap.GetSizeByGen(1)));
            logger?.WriteLine(LogKind.Info, string.Format("  Gen2: {0,10:N0} bytes", heap.GetSizeByGen(2)));
            logger?.WriteLine(LogKind.Info, string.Format("   LOH: {0,10:N0} bytes", heap.GetSizeByGen(3)));

            logger?.WriteLine(LogKind.Info, "  Segments: " + heap.Segments.Count);
            foreach (var segment in heap.Segments)
            {
                logger?.WriteLine(LogKind.Info,
                                  string.Format("    Segment: {0,10:N0} bytes, {1,10}, Gen0: {2,10:N0} bytes, Gen1: {3,10:N0} bytes, Gen2: {4,10:N0} bytes",
                                                segment.Length,
                                                segment.IsLarge ? "Large" : (segment.IsEphemeral ? "Ephemeral" : "Unknown"),
                                                segment.Gen0Length,
                                                segment.Gen1Length,
                                                segment.Gen2Length));
            }

            logger?.WriteLine();
        }
Esempio n. 13
0
        private MetadataRegion FindRegion(ulong address)
        {
            if (!_regionInitialized)
            {
                _regionInitialized = true;

                Trace.TraceInformation($"FindRegion: initializing regions for runtime #{_runtime.Id}");
                ClrRuntime clrruntime = _runtime.Services.GetService <ClrRuntime>();
                if (clrruntime != null)
                {
                    _regions = clrruntime.EnumerateModules()
                               .Where((module) => module.MetadataAddress != 0 && module.IsPEFile && !module.IsDynamic)
                               .Select((module) => new MetadataRegion(this, module))
                               .ToImmutableArray()
                               .Sort();
                }
            }

            if (_regions != null)
            {
                int min = 0, max = _regions.Length - 1;
                while (min <= max)
                {
                    int            mid    = (min + max) / 2;
                    MetadataRegion region = _regions[mid];

                    if (address >= region.StartAddress && address < region.EndAddress)
                    {
                        return(region);
                    }

                    if (region.StartAddress < address)
                    {
                        min = mid + 1;
                    }
                    else
                    {
                        max = mid - 1;
                    }
                }
            }

            return(null);
        }
Esempio n. 14
0
        public void NoDuplicateModules()
        {
            // Modules should have a unique .Address.
            // https://github.com/microsoft/clrmd/issues/440

            using DataTarget dt      = TestTargets.AppDomains.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            HashSet <ulong> seen = new HashSet <ulong> {
                0
            };
            HashSet <ClrModule> seenModules = new HashSet <ClrModule> {
                null
            };

            foreach (ClrModule module in runtime.EnumerateModules())
            {
                Assert.True(seenModules.Add(module));
                Assert.True(seen.Add(module.Address));
            }
        }
Esempio n. 15
0
        public void RuntimeTests(TestHost host)
        {
            // The current Linux test assets are not alpine/musl
            if (OS.IsAlpine)
            {
                throw new SkipTestException("Not supported on Alpine Linux");
            }
            var runtimeService = host.Target.Services.GetService <IRuntimeService>();

            Assert.NotNull(runtimeService);

            var contextService = host.Target.Services.GetService <IContextService>();

            Assert.NotNull(contextService);
            Assert.NotNull(contextService.GetCurrentRuntime());

            foreach (ImmutableDictionary <string, TestDataReader.Value> runtimeData in host.TestData.Runtimes)
            {
                if (runtimeData.TryGetValue("Id", out int id))
                {
                    IRuntime runtime = runtimeService.EnumerateRuntimes().FirstOrDefault((r) => r.Id == id);
                    Assert.NotNull(runtime);

                    runtimeData.CompareMembers(runtime);

                    ClrInfo clrInfo = runtime.Services.GetService <ClrInfo>();
                    Assert.NotNull(clrInfo);

                    ClrRuntime clrRuntime = runtime.Services.GetService <ClrRuntime>();
                    Assert.NotNull(clrRuntime);
                    Assert.NotEmpty(clrRuntime.AppDomains);
                    Assert.NotEmpty(clrRuntime.Threads);
                    Assert.NotEmpty(clrRuntime.EnumerateModules());
                    if (!host.DumpFile.Contains("Triage"))
                    {
                        Assert.NotEmpty(clrRuntime.EnumerateHandles());
                    }
                }
            }
        }
Esempio n. 16
0
        public void TestTypeMapRoundTrip()
        {
            using DataTarget dt      = TestTargets.Types.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            int badTypes = 0;

            foreach (ClrModule module in runtime.EnumerateModules())
            {
                foreach ((ulong mt, int token) in module.EnumerateTypeDefToMethodTableMap())
                {
                    Assert.NotEqual(0, token);
                    Assert.True((token & 0x02000000) == 0x02000000);

                    ClrType type = runtime.GetTypeByMethodTable(mt);
                    if (type == null)
                    {
                        // We really want to Assert.NotNull(type), but it turns out that one type
                        // (System.Runtime.Remoting.Proxies.__TransparentProxy) cannot be constructed because
                        // GetMethodTableData returns null for it.  This is an issue with the dac so we'll
                        // simply count types that are null and assert there's only one

                        badTypes++;

                        continue;
                    }

                    Assert.NotNull(type);

                    ClrType typeFromToken = module.ResolveToken(token);
                    Assert.NotNull(typeFromToken);

                    Assert.Same(type, typeFromToken);
                }
            }

            Assert.True(badTypes <= 1);
        }
Esempio n. 17
0
        public void PdbEqualityTest()
        {
            // Ensure all methods in our source file is in the pdb.
            using DataTarget dt      = TestTargets.NestedException.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            PdbInfo[] allPdbs = runtime.EnumerateModules().Select(m => m.Pdb).Where(pdb => pdb != null).ToArray();
            Assert.True(allPdbs.Length > 1);

            for (int i = 0; i < allPdbs.Length; i++)
            {
                Assert.NotNull(allPdbs[i]);
                Assert.True(allPdbs[i].Equals(allPdbs[i]));
                for (int j = i + 1; j < allPdbs.Length; j++)
                {
                    if (allPdbs[i].Path != allPdbs[j].Path)
                    {
                        Assert.False(allPdbs[i].Equals(allPdbs[j]));
                        Assert.False(allPdbs[j].Equals(allPdbs[i]));
                    }
                }
            }
        }
Esempio n. 18
0
        public void TypeEqualityTest()
        {
            // This test ensures that only one ClrType is created when we have a type loaded into two different AppDomains with two different
            // method tables.

            const string TypeName = "Foo";

            using DataTarget dt      = TestTargets.AppDomains.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();
            ClrHeap heap = runtime.Heap;

            ClrType[] types = (from obj in heap.EnumerateObjects()
                               let t = heap.GetObjectType(obj.Address)
                                       where t.Name == TypeName
                                       orderby t.MethodTable
                                       select t).ToArray();

            Assert.Equal(2, types.Length);
            Assert.NotSame(types[0], types[1]);

            ClrType[] typesFromModule = (from module in runtime.EnumerateModules()
                                         let name = Path.GetFileNameWithoutExtension(module.Name)
                                                    where name.Equals("sharedlibrary", StringComparison.OrdinalIgnoreCase)
                                                    let type = module.GetTypeByName(TypeName)
                                                               select type).ToArray();

            Assert.Equal(2, typesFromModule.Length);
            Assert.NotSame(types[0], types[1]);
            Assert.NotEqual(types[0], types[1]);

            if (dt.CacheOptions.CacheTypes)
            {
                Assert.Same(types[0], typesFromModule[0]);
                Assert.Same(types[1], typesFromModule[1]);
            }
            else
            {
                Assert.Equal(types[0], typesFromModule[0]);
                Assert.Equal(types[1], typesFromModule[1]);
            }

            // Get new types
            runtime.FlushCachedData();

            ClrType[] newTypes = (from module in runtime.EnumerateModules()
                                  let name = Path.GetFileNameWithoutExtension(module.Name)
                                             where name.Equals("sharedlibrary", StringComparison.OrdinalIgnoreCase)
                                             let type = module.GetTypeByName(TypeName)
                                                        select type).ToArray();

            Assert.Equal(2, newTypes.Length);
            for (int i = 0; i < newTypes.Length; i++)
            {
                Assert.NotSame(typesFromModule[i], newTypes[i]);
                Assert.Equal(typesFromModule[i], newTypes[i]);
            }

            // Even though these are the same underlying type defined in sharedlibrary's metadata,
            // they have different MethodTables, Parent modules, and parent domains.  These do not
            // compare as equal.
            Assert.NotEqual(typesFromModule[0], typesFromModule[1]);
        }
Esempio n. 19
0
        public void EnsureFlushClearsData()
        {
            using DataTarget dt      = TestTargets.AppDomains.LoadFullDump();
            using ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            var oldShared       = runtime.SharedDomain;
            var oldSystem       = runtime.SystemDomain;
            var oldDomains      = runtime.AppDomains;
            var oldHeap         = runtime.Heap;
            var oldModules      = runtime.EnumerateModules().ToArray();
            var oldObjects      = oldHeap.EnumerateObjects().Take(20).ToArray();
            var oldFields       = oldObjects.SelectMany(o => o.Type.Fields).ToArray();
            var oldStaticFields = oldObjects.SelectMany(o => o.Type.StaticFields).ToArray();
            var oldMethods      = oldObjects.SelectMany(o => o.Type.Methods).ToArray();
            var oldThreads      = runtime.Threads;

            // Ensure names are read and cached
            foreach (var obj in oldObjects)
            {
                _ = obj.Type.Name;
                foreach (var item in obj.Type.Methods)
                {
                    _ = item.Name;
                }
                foreach (var item in obj.Type.Fields)
                {
                    _ = item.Name;
                }
                foreach (var item in obj.Type.StaticFields)
                {
                    _ = item.Name;
                }
            }

            foreach (var module in oldModules)
            {
                _ = module.Name;
                _ = module.FileName;
                _ = module.AssemblyName;
            }

            // Ensure we have some data to compare against
            Assert.NotEmpty(oldDomains);
            Assert.NotEmpty(oldModules);
            Assert.NotEmpty(oldObjects);
            Assert.NotEmpty(oldThreads);
            Assert.NotEmpty(oldFields);
            Assert.NotEmpty(oldStaticFields);
            Assert.NotEmpty(oldMethods);

            // Make sure we aren't regenerating this list every time.
            Assert.Same(oldDomains, runtime.AppDomains);

            // Clear all cached data.
            runtime.FlushCachedData();

            CheckDomainNotSame(oldShared, runtime.SharedDomain);
            CheckDomainNotSame(oldSystem, runtime.SystemDomain);
            Assert.Equal(oldDomains.Count, runtime.AppDomains.Count);
            for (int i = 0; i < oldDomains.Count; i++)
            {
                CheckDomainNotSame(oldDomains[i], runtime.AppDomains[i]);
            }

            var newModules = runtime.EnumerateModules().ToArray();

            for (int i = 0; i < oldModules.Length; i++)
            {
                CheckModuleNotSame(oldModules[i], newModules[i]);
            }

            ClrHeap newHeap = runtime.Heap;

            var newObjs = newHeap.EnumerateObjects().Take(20).ToArray();

            Assert.Equal(oldObjects.Length, newObjs.Length);
            for (int i = 0; i < oldObjects.Length; i++)
            {
                Assert.Equal(oldObjects[i].Address, newObjs[i].Address);
                CheckTypeNotSame(oldObjects[i].Type, newObjs[i].Type);
            }

            var newThreads = runtime.Threads;

            Assert.Same(newThreads, runtime.Threads);
            Assert.Equal(oldThreads.Count, newThreads.Count);
            for (int i = 0; i < oldThreads.Count; i++)
            {
                Assert.Equal(oldThreads[i].OSThreadId, newThreads[i].OSThreadId);
                Assert.NotSame(oldThreads[i], newThreads[i]);
            }
        }