internal override unsafe void Visit(UIntPtr *loc) { UIntPtr objAddr = *loc; Object obj = Magic.fromAddress(objAddr); // 1. remove from ZCT Remove(obj); // 2. decrement RC on objects retained via multiuseword MultiUseWord muw = MultiUseWord.GetForObject(obj); if (muw.IsMonitorOrInflatedTag()) { MultiUseWord.RefCountGCDeadObjHook(muw); } // 3. add to deallocation list DeferredReferenceCountingCollector.deallocateLazily(obj); }
internal static void ReportHeapDetails() { VTable.DebugPrint("\nHeap details:\n"); uint pageCount = 0; for (UIntPtr i = UIntPtr.Zero; i < PageTable.pageTableCount; i++) { if (PageTable.IsMyGcPage(i)) { pageCount++; } } VTable.DebugPrint("\tTotal number of heap pages: {0}", __arglist(pageCount)); // The following obtains counts of heap objects against types. UIntPtr lowPage = UIntPtr.Zero; UIntPtr highPage = PageTable.pageTableCount; assertRuntimeTypeHeaders(lowPage, highPage); // First count the RuntimeType instances for heap objects. runtimeTypeReckoner.Initialize(true); visitAllObjects(forGCRuntimeTypeReckoner, lowPage, highPage); // Next, create a table for RuntimeType instance accounting. // NOTE: Storage for the table is marked "non-GC". Since // static data accounting is done before this, it's okay. int numSlots = runtimeTypeReckoner.Count; if (numSlots > TABLE_SIZE) { VTable.DebugPrint("Need {0} slots, have {1}\n", __arglist(numSlots, TABLE_SIZE)); VTable.NotReached("MemoryAccounting table not large enough"); } // Associate a table slot for each RuntimeType instance. runtimeTypeMapper.Initialize(false, MemoryAccounting.table); visitAllObjects(forGCRuntimeTypeMapper, lowPage, highPage); // Map each relevant RuntimeType instance to its table slot. for (uint i = 0; i < numSlots; i++) { RuntimeType rType = MemoryAccounting.table[i].RuntimeTypeObject; VTable.Assert(!MultiUseWord.IsMarked(rType), @"!MultiUseWord.IsMarked(rType)"); MemoryAccounting.table[i].SavedMUW = MultiUseWord.GetForObject(rType); MultiUseWord.SetValForObject(rType, (UIntPtr)i); } // Count heap object instances by RuntimeType using table. instanceReckoner.Initialize(MemoryAccounting.table); visitAllObjects(forGCInstanceReckoner, lowPage, highPage); // Bubble sort the table in decreasing order of total size. for (int i = 0; i < numSlots; i++) { for (int j = numSlots - 1; j > i; j--) { if (MemoryAccounting.table[j].TotalSize > MemoryAccounting.table[j - 1].TotalSize) { // Swap contents. RuntimeTypeAccounting temp = MemoryAccounting.table[j]; MemoryAccounting.table[j] = MemoryAccounting.table[j - 1]; MemoryAccounting.table[j - 1] = temp; } } } // Display table. VTable.DebugPrint("\n\tCounts of objects against types:\n"); for (uint i = 0; i < numSlots; i++) { if ((uint)MemoryAccounting.table[i].TotalSize < 1024) { continue; } VTable.DebugPrint ("\t\t{0,36} instances: {1,6}, bytes: {2,10}\n", __arglist(MemoryAccounting.table[i].RuntimeTypeObject.Name, (uint)MemoryAccounting.table[i].Count, (uint)MemoryAccounting.table[i].TotalSize)); } // Reset book-keeping information maintained in headers and the global // table. for (uint i = 0; i < numSlots; i++) { RuntimeType rType = MemoryAccounting.table[i].RuntimeTypeObject; MultiUseWord.SetForObject (rType, MemoryAccounting.table[i].SavedMUW); VTable.Assert(!MultiUseWord.IsMarked(rType), "@!MultiUseWord.IsMarked(rType)"); MemoryAccounting.table[i].RuntimeTypeObject = null; MemoryAccounting.table[i].SavedMUW = new MultiUseWord(new UIntPtr(0)); MemoryAccounting.table[i].TotalSize = new UIntPtr(0); MemoryAccounting.table[i].Count = 0; } }