protected static void deallocateObjects (NonNullReferenceVisitor decrementer) { int startTicks = 0; bool enableGCTiming = VTable.enableGCTiming; if (enableGCTiming) { VTable.enableGCTiming = false; startTicks = Environment.TickCount; } if (VTable.enableGCWatermarks) { MemoryAccounting.RecordHeapWatermarks(); } // Set up a block to deallocate, if one doesn't exist. if (beingDeallocatedBlock == null && delayedDeallocationList != null) { beingDeallocatedBlock = delayedDeallocationList; delayedDeallocationList = getNextLink(delayedDeallocationList); delayedDeallocationLength--; UIntPtr objAddr = Magic.addressOf(beingDeallocatedBlock); VTable vtable = beingDeallocatedBlock.vtable; initIncrementalDecrement(objAddr, vtable); } // Perform up to a constant number of work chunks on the // block being deallocated. A "work chunk" is either // decrementing up to a fixed number of references held in // an object, decrementing up to a fixed number of slots // if the object is an array, or reclaiming the object // after all decrements on its internal contents are done. for (uint workDone = 0; beingDeallocatedBlock != null && workDone < deallocationSpan; workDone++) { // Continue work on block. UIntPtr objAddr = Magic.addressOf(beingDeallocatedBlock); #if DEBUG UIntPtr page = PageTable.Page(objAddr); VTable.Assert(PageTable.IsGcPage(page), @"PageTable.IsGcPage(page)"); #endif // DEBUG VTable vtable = beingDeallocatedBlock.vtable; if (incrementalDecrement(objAddr, vtable, decrementer) != 0) { continue; } // All decrements on contained references are over. Object obj = beingDeallocatedBlock; VTable.Assert((obj.REF_STATE & RSMasks.refCount) == 0, @"(obj.REF_STATE & RSMasks.refCount) == 0"); #if DEBUG PLCLink *plcLinkAddr = GetPLCLink(obj); VTable.Assert(plcLinkAddr == null, @"plcLinkAddr == null"); #endif // DEBUG SegregatedFreeList.Free(obj); // Set up block to work on next. beingDeallocatedBlock = delayedDeallocationList; if (delayedDeallocationList != null) { delayedDeallocationList = getNextLink(delayedDeallocationList); delayedDeallocationLength--; objAddr = Magic.addressOf(beingDeallocatedBlock); vtable = beingDeallocatedBlock.vtable; initIncrementalDecrement(objAddr, vtable); } } SegregatedFreeList.RecycleGlobalPages(); SegregatedFreeList.CommitFreedData(); GC.newBytesSinceGC = UIntPtr.Zero; if (enableGCTiming) { int elapsedTicks = Environment.TickCount - startTicks; System.GC.gcTotalTime += elapsedTicks; if (System.GC.maxPauseTime < elapsedTicks) { System.GC.maxPauseTime = elapsedTicks; } System.GC.pauseCount++; VTable.enableGCTiming = true; } }
private static unsafe void processPLCList() { int startTicks = 0; bool enableGCTiming = VTable.enableGCTiming; if (enableGCTiming) { VTable.enableGCTiming = false; startTicks = Environment.TickCount; } if (VTable.enableGCWatermarks) { MemoryAccounting.RecordHeapWatermarks(); } #if DEBUG VTable.Assert(firstPLCLink->objAddr == UIntPtr.Zero, @"firstPLCLink->objAddr == UIntPtr.Zero"); #endif // DEBUG // Let S be the subgraph of heap objects reachable from // the PLC list. Decrement counts due to references in S. for (PLCLink *link = firstPLCLink->next; link != null; link = link->next) { UIntPtr objAddr = link->objAddr; VTable.Assert(objAddr != UIntPtr.Zero, @"objAddr != UIntPtr.Zero"); Object obj = Magic.fromAddress(objAddr); VTable.Assert((obj.REF_STATE & countingONFlagMask) != 0, @"(obj.REF_STATE & countingONFlagMask) != 0"); uint refState = obj.REF_STATE; if ((refState & markFlagMask) == 0) { obj.REF_STATE = refState | markFlagMask; internalDecrementer.Traverse(objAddr); } } // Objects that now have non-zero counts are those that // have references external to S incident on them. // Recompute counts due to reachability from such objects. for (PLCLink *link = firstPLCLink->next; link != null; link = link->next) { UIntPtr objAddr = link->objAddr; internalScanner.Traverse(objAddr); } // String together objects with reference count // of zero for reclamation. internalReclaimer.Initialize(); for (PLCLink *link = firstPLCLink->next; link != null; link = link->next) { UIntPtr objAddr = link->objAddr; internalReclaimer.Traverse(objAddr); } ulong reclaimedBytes = 0; Object reclaimedObj = internalReclaimer.ReclaimedObjects; while (reclaimedObj != null) { if (VTable.enableGCProfiling) { UIntPtr size = ObjectLayout.Sizeof(reclaimedObj); reclaimedBytes += (ulong)size; } Object nextReclaimedObj = getNextLink(reclaimedObj); SegregatedFreeList.Free(reclaimedObj); reclaimedObj = nextReclaimedObj; } // Recycle the PLC list. if (firstPLCLink->next != null) { PLCLink *lastPLCLink = firstPLCLink; do { lastPLCLink = lastPLCLink->next; } while (lastPLCLink->next != null); lastPLCLink->next = plcListChunk; plcListChunk = firstPLCLink->next; firstPLCLink->next = null; } // Release the memory used up by work lists. UIntPtrQueue.ReleaseStandbyPages(null); SegregatedFreeList.RecycleGlobalPages(); SegregatedFreeList.CommitFreedData(); GC.newBytesSinceGC = UIntPtr.Zero; if (enableGCTiming) { int elapsedTicks = Environment.TickCount - startTicks; System.GC.gcTotalTime += elapsedTicks; if (System.GC.maxPauseTime < elapsedTicks) { System.GC.maxPauseTime = elapsedTicks; } System.GC.pauseCount++; VTable.enableGCTiming = true; } if (VTable.enableGCProfiling) { if (maxCyclicGarbage < reclaimedBytes) { maxCyclicGarbage = reclaimedBytes; } totalCyclicGarbage += reclaimedBytes; cycleCollections++; } }
private void PerformCollection(int currentThreadIndex, int generation) { // Clear the GCRequest bit (if necessary) before doing // anything that could cause a state transition. if (Transitions.HasGCRequest(currentThreadIndex)) { Transitions.ClearGCRequest(currentThreadIndex); } int startTicks = 0; bool enableGCTiming = VTable.enableGCTiming; if (enableGCTiming || VTable.enableFinalGCTiming) { VTable.enableGCTiming = false; startTicks = Environment.TickCount; if (enableGCTiming) { VTable.DebugPrint("[GC start: {0} bytes]\n", __arglist(TotalMemory)); } } #if SINGULARITY Tracing.Log(Tracing.Debug, "GC start"); #endif CollectorStatistics.Event(GCEvent.StopTheWorld); CurrentPhase = StopTheWorldPhase.Synchronizing; StopTheWorld(); CurrentPhase = StopTheWorldPhase.SingleThreaded; StartGCCycle(); #if SINGULARITY long preGcMemoryUsage = GC.GetTotalMemory(false); #if SINGULARITY_KERNEL #if THREAD_TIME_ACCOUNTING TimeSpan ticks = Thread.CurrentThread.ExecutionTime; TimeSpan ticks2 = SystemClock.KernelUpTime; #else TimeSpan ticks = SystemClock.KernelUpTime; #endif #elif SINGULARITY_PROCESS #if THREAD_TIME_ACCOUNTING TimeSpan ticks = ProcessService.GetThreadTime(); TimeSpan ticks2 = ProcessService.GetUpTime(); #else TimeSpan ticks = ProcessService.GetUpTime(); #endif #endif #endif //singularity #if SINGULARITY_KERNEL bool iflag = Processor.DisableInterrupts(); // Disable interrupts on other CPU's MpExecution.StopProcessorsForGC(); #endif #if SINGULARITY ulong beg = Isa.GetCycleCount(); #endif // Preparation GC.allocationGCInhibitCount++; // Verify the heap before GC if (VTable.enableGCVerify) { this.VerifyHeap(true); } // Invoke the chosen collector #if SINGULARITY Monitoring.Log(Monitoring.Provider.GC, (ushort)GarbageCollectorEvent.StartCollection); #endif this.CollectStopped(collectorThreadIndex, generation); #if SINGULARITY Monitoring.Log(Monitoring.Provider.GC, (ushort)GarbageCollectorEvent.EndCollection); #endif // Verify the heap after GC if (VTable.enableGCVerify) { this.VerifyHeap(false); } if (VTable.enableGCAccounting) { MemoryAccounting.Report(GC.gcType); } // Cleanup CollectorStatistics.Event(GCEvent.ResumeTheWorld); GC.allocationGCInhibitCount--; CurrentPhase = StopTheWorldPhase.Idle; #if SINGULARITY long postGcMemoryUsage = GC.GetTotalMemory(false); #endif if (enableGCTiming || VTable.enableFinalGCTiming) { int elapsedTicks = Environment.TickCount - startTicks; BaseCollector.RegisterPause(elapsedTicks); if (enableGCTiming) { VTable.DebugPrint("[GC end : {0} bytes, {1} ms]\n", __arglist(TotalMemory, elapsedTicks)); VTable.enableGCTiming = true; } } if (VTable.enableGCProfiling) { ulong totalMemory = (ulong)GC.GetTotalMemory(false); this.RegisterHeapSize(totalMemory); } ResumeTheWorld(); collectorThreadIndex = -1; #if SINGULARITY Tracing.Log(Tracing.Debug, "GC stop"); long pagesCollected = preGcMemoryUsage - postGcMemoryUsage; #if SINGULARITY_KERNEL #if THREAD_TIME_ACCOUNTING int procId = Thread.CurrentProcess.ProcessId; ticks = Thread.CurrentThread.ExecutionTime - ticks; ticks2 = SystemClock.KernelUpTime - ticks2; Process.kernelProcess.SetGcPerformanceCounters(ticks, (long)pagesCollected); #else ticks = SystemClock.KernelUpTime - ticks; #endif Thread.CurrentProcess.SetGcPerformanceCounters(ticks, (long)pagesCollected); #elif SINGULARITY_PROCESS #if THREAD_TIME_ACCOUNTING ushort procId = ProcessService.GetCurrentProcessId(); ticks = ProcessService.GetThreadTime() - ticks; ticks2 = ProcessService.GetUpTime() - ticks2; #else ticks = ProcessService.GetUpTime() - ticks; #endif ProcessService.SetGcPerformanceCounters(ticks, (long)pagesCollected); #endif #if DEBUG #if THREAD_TIME_ACCOUNTING DebugStub.WriteLine("~~~~~ StopTheWorld [collected pages={0:x8}, pid={1:x3}, ms(Thread)={2:d6}, ms(System)={3:d6}, procId={4}, tid={5}]", __arglist(pagesCollected, PageTable.processTag >> 16, ticks.Milliseconds, ticks2.Milliseconds, procId, Thread.GetCurrentThreadIndex() )); #endif #endif #endif #if SINGULARITY DebugStub.AddToPerfCounter(GC.perfCounter, Isa.GetCycleCount() - beg); #endif #if SINGULARITY_KERNEL // Resume interrupts on other CPU's MpExecution.ResumeProcessorsAfterGC(); Processor.RestoreInterrupts(iflag); #endif }