/// <summary> /// Creates a new garbage collector /// </summary> /// <param name="virtualMachine">The virtual machine</param> public GarbageCollector(VirtualMachine virtualMachine) { this.virtualMachine = virtualMachine; this.youngGeneration = new CollectorGeneration( virtualMachine.MemoryManager, virtualMachine.ManagedObjectReferences, 4 * 1024 * 1024); }
/// <summary> /// Marks the given value /// </summary> /// <param name="generation">The generation</param> /// <param name="value">The value</param> /// <param name="type">The type of the value</param> private void MarkValue(CollectorGeneration generation, long value, BaseType type) { if (type.IsReference) { //Don't mark nulls if (value == 0) { return; } this.MarkObject(generation, this.GetObjectReference(new IntPtr(value))); } }
/// <summary> /// Sweeps the objects in the given generation /// </summary> /// <param name="generation">The generation</param> private void SweepObjects(CollectorGeneration generation) { generation.Heap.VisitObjects(objectReference => { if (objectReference.IsMarked) { objectReference.Unmark(); objectReference.IncreaseSurvivalCount(); } else { if (this.virtualMachine.Config.EnableDebug && this.virtualMachine.Config.PrintDeallocation) { RuntimeInterface.DebugLog($"Deleted object {objectReference}"); } this.DeleteObject(objectReference); } }); }
/// <summary> /// Marks all the objects starting at the given frame /// </summary> /// <param name="generation">The generation</param> /// <param name="stackFrame">The stack frame</param> private void MarkAllObjects(CollectorGeneration generation, StackFrame stackFrame) { var stalkWalker = new StackWalker(this.virtualMachine.CallStack); stalkWalker.VisitObjectReferences( stackFrame, frameEntry => { var objectPointer = new IntPtr(frameEntry.Value); this.MarkObject(generation, this.GetObjectReference(objectPointer)); }, frame => { if (this.virtualMachine.Config.EnableDebug && this.virtualMachine.Config.PrintStackFrameWhenGC) { RuntimeInterface.DebugLog($"{frame.Function.Definition.Name} ({frame.InstructionIndex})"); RuntimeInterface.PrintStackFrame(frame, false); } }); }
/// <summary> /// Allocates an object of the given size /// </summary> /// <param name="generation">The generation to allocate in</param> /// <param name="type">The type of the object</param> /// <param name="size">The size of the object</param> private IntPtr AllocateObject(CollectorGeneration generation, BaseType type, int size) { var fullSize = Constants.ObjectHeaderSize + size; var objectPointer = generation.Allocate(fullSize); NativeHelpers.SetBlock(objectPointer, fullSize, 0); //Set the header var typeObjectRef = this.virtualMachine.GetManagedReference(type); NativeHelpers.SetInt(objectPointer, 0, typeObjectRef); //Type NativeHelpers.SetByte(objectPointer, Constants.ManagedObjectReferenceSize, 0); //GC info var dataPointer = objectPointer + Constants.ObjectHeaderSize; if (this.virtualMachine.Config.LogAllocation) { this.Allocations.Add(dataPointer); } //The returned ptr is to the data return(dataPointer); }
/// <summary> /// Marks the given object /// </summary> /// <param name="generation">The generation</param> /// <param name="objectReference">A reference to the object</param> private void MarkObject(CollectorGeneration generation, ObjectReference objectReference) { if (!objectReference.IsMarked) { objectReference.Mark(); if (objectReference.Type.IsArray) { //Mark ref elements var arrayType = (ArrayType)objectReference.Type; if (arrayType.ElementType.IsReference) { var arrayReference = new ArrayReference(objectReference); for (int i = 0; i < arrayReference.Length; i++) { var elementPtr = arrayReference.GetElement(i); this.MarkValue(generation, NativeHelpers.ReadLong(elementPtr), arrayType.ElementType); } } } else if (objectReference.Type.IsClass) { //Mark ref fields var classType = (ClassType)objectReference.Type; foreach (var field in classType.Metadata.Fields) { if (field.Type.IsReference) { var fieldValue = NativeHelpers.ReadLong(objectReference.DataPointer + field.LayoutOffset); this.MarkValue(generation, fieldValue, field.Type); } } } } }