Example #1
0
        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;
            }
        }
Example #2
0
        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
        }