static DynamicJsonValue ToJson(GCMemoryInfo info) { return(new DynamicJsonValue { [nameof(info.Compacted)] = info.Compacted, [nameof(info.Concurrent)] = info.Concurrent, [nameof(info.FinalizationPendingCount)] = info.FinalizationPendingCount, [nameof(info.FragmentedBytes)] = info.FragmentedBytes, [nameof(info.Generation)] = info.Generation, [nameof(info.GenerationInfo)] = new DynamicJsonArray(info.GenerationInfo.ToArray().Select(x => new DynamicJsonValue { [nameof(x.FragmentationAfterBytes)] = x.FragmentationAfterBytes, [nameof(x.FragmentationBeforeBytes)] = x.FragmentationBeforeBytes, [nameof(x.SizeAfterBytes)] = x.SizeAfterBytes, [nameof(x.SizeBeforeBytes)] = x.SizeBeforeBytes })), [nameof(info.HeapSizeBytes)] = info.HeapSizeBytes, [nameof(info.HighMemoryLoadThresholdBytes)] = info.HighMemoryLoadThresholdBytes, [nameof(info.Index)] = info.Index, [nameof(info.MemoryLoadBytes)] = info.MemoryLoadBytes, [nameof(info.PauseDurations)] = new DynamicJsonArray(info.PauseDurations.ToArray().Cast <object>()), [nameof(info.PauseTimePercentage)] = info.PauseTimePercentage, [nameof(info.PinnedObjectsCount)] = info.PinnedObjectsCount, [nameof(info.PromotedBytes)] = info.PromotedBytes, [nameof(info.TotalAvailableMemoryBytes)] = info.TotalAvailableMemoryBytes, [nameof(info.TotalCommittedBytes)] = info.TotalCommittedBytes }); }
public static int Main() { Stopwatch sw = Stopwatch.StartNew(); GC.Collect(); sw.Stop(); TimeSpan elapsed = sw.Elapsed; TimeSpan totalPauseDuration = GC.GetTotalPauseDuration(); GCMemoryInfo memoryInfo = GC.GetGCMemoryInfo(); TimeSpan lastGcDuration = memoryInfo.PauseDurations[0]; // These conditions assume the only GC in the process // is the one we just triggered. This makes the test incompatible // with any changes that might introduce extra GCs. if (TimeSpan.Zero < totalPauseDuration && totalPauseDuration <= elapsed && lastGcDuration == totalPauseDuration) { return(100); } else { return(101); } }
async Task <IndexViewModel> GetIndexViewModel() { var indexViewModel = new IndexViewModel(); GCMemoryInfo gcInfo = GC.GetGCMemoryInfo(); indexViewModel.TotalAvailableMemory = GetInBestUnit(gcInfo.TotalAvailableMemoryBytes); indexViewModel.HostName = Dns.GetHostName(); indexViewModel.IpList = await Dns.GetHostAddressesAsync(indexViewModel.HostName); indexViewModel.cGroup = RuntimeInformation.OSDescription.StartsWith("Linux") && Directory.Exists("/sys/fs/cgroup/memory") && Directory.Exists("/sys/fs/cgroup/cpu"); _logger.LogInformation($"running in cgroup? : {indexViewModel.cGroup}"); if (indexViewModel.cGroup) { string usage = System.IO.File.ReadAllLines("/sys/fs/cgroup/memory/memory.usage_in_bytes")[0]; string limit = System.IO.File.ReadAllLines("/sys/fs/cgroup/memory/memory.limit_in_bytes")[0]; string cpuQuota = System.IO.File.ReadAllLines("/sys/fs/cgroup/cpu/cpu.cfs_quota_us")[0]; string cpuPeriod = System.IO.File.ReadAllLines("/sys/fs/cgroup/cpu/cpu.cfs_period_us")[0]; indexViewModel.CpuShares = System.IO.File.ReadAllLines("/sys/fs/cgroup/cpu/cpu.shares")[0]; indexViewModel.MemoryUsage = GetInBestUnit(long.Parse(usage)); indexViewModel.MemoryLimit = GetInBestUnit(long.Parse(limit)); indexViewModel.CpuLimit = GetCpuLimit(long.Parse(cpuQuota), long.Parse(cpuPeriod)); } return(indexViewModel); }
protected override int GetCurrentPressure() { // Try to refresh GC stats if they haven't been updated since our last check. int ccount = GC.CollectionCount(0); if (ccount == lastGCCount) { GC.Collect(0, GCCollectionMode.Optimized); // A quick, ephemeral Gen 0 collection ccount = GC.CollectionCount(0); } lastGCCount = ccount; // Get stats from GC. GCMemoryInfo memInfo = GC.GetGCMemoryInfo(); if (memInfo.TotalAvailableMemoryBytes >= memInfo.MemoryLoadBytes) { int memoryLoad = (int)((float)memInfo.MemoryLoadBytes * 100.0 / (float)memInfo.TotalAvailableMemoryBytes); return(Math.Max(1, memoryLoad)); } // It's possible the load was legitimately higher than "available". In that case, return 100. // Otherwise, return 0 to minimize impact because something was unexpected. return((memInfo.MemoryLoadBytes > 0) ? 100 : 0); }
public static void ViewMemoryAtMoment(string moment) { long threadMemory = GC.GetAllocatedBytesForCurrentThread(); GCMemoryInfo gcInfo = GC.GetGCMemoryInfo(); long totalMemory = GC.GetTotalMemory(false); Console.WriteLine("[Memory][{0}] allocatedbytesAtThread = {1}, totalMemory = {2}", moment, threadMemory, totalMemory); }
public static bool PrintGCMemoryInfo(GCKind kind) { if (!fPrintInfo) { return(true); } GCMemoryInfo memoryInfo = GC.GetGCMemoryInfo(kind); Console.WriteLine("last recorded {0} GC#{1}, collected gen{2}, concurrent: {3}, compact: {4}, promoted {5:N0} bytes", kind, memoryInfo.Index, memoryInfo.Generation, memoryInfo.Concurrent, memoryInfo.Compacted, memoryInfo.PromotedBytes); Console.WriteLine("GC pause: {0:N0}, {1:N0}", memoryInfo.PauseDurations[0].TotalMilliseconds, memoryInfo.PauseDurations[1].TotalMilliseconds); Console.WriteLine("Total committed {0:N0}, % Pause time in GC: {1}", memoryInfo.TotalCommittedBytes, memoryInfo.PauseTimePercentage); Console.WriteLine("This GC observed {0:N0} pinned objects and {1:N0} objects ready for finalization", memoryInfo.PinnedObjectsCount, memoryInfo.FinalizationPendingCount); int numGenerations = memoryInfo.GenerationInfo.Length; Console.WriteLine("there are {0} generations", numGenerations); for (int i = 0; i < numGenerations; i++) { Console.WriteLine("gen#{0}, size {1:N0}->{2:N0}, frag {3:N0}->{4:N0}", i, memoryInfo.GenerationInfo[i].SizeBeforeBytes, memoryInfo.GenerationInfo[i].SizeAfterBytes, memoryInfo.GenerationInfo[i].FragmentationBeforeBytes, memoryInfo.GenerationInfo[i].FragmentationAfterBytes); } if (kind == GCKind.Ephemeral) { if (memoryInfo.Generation == GC.MaxGeneration) { Console.WriteLine("FAILED: GC#{0} is supposed to be an ephemeral GC but condemned max gen", memoryInfo.Index); return(false); } } else if (kind == GCKind.FullBlocking) { if ((memoryInfo.Generation != GC.MaxGeneration) || memoryInfo.Concurrent) { Console.WriteLine("FAILED: GC#{0} is supposed to be a full blocking GC but gen is {1}, concurrent {2}", memoryInfo.Index, memoryInfo.Generation, memoryInfo.Concurrent); return(false); } } else if (kind == GCKind.Background) { if ((memoryInfo.Generation != GC.MaxGeneration) || !(memoryInfo.Concurrent)) { Console.WriteLine("FAILED: GC#{0} is supposed to be a BGC but gen is {1}, concurrent {2}", memoryInfo.Index, memoryInfo.Generation, memoryInfo.Concurrent); return(false); } } return(true); }
private bool OnGen2GCCallback() { // Gen 2 GCs may be very infrequent in some cases. If it becomes an issue, consider updating the memory usage more // frequently. The memory usage is only used for fallback purposes in blocking adjustment, so an artificially higher // memory usage may cause blocking adjustment to fall back to slower adjustments sooner than necessary. GCMemoryInfo gcMemoryInfo = GC.GetGCMemoryInfo(); _memoryLimitBytes = gcMemoryInfo.HighMemoryLoadThresholdBytes; _memoryUsageBytes = Math.Min(gcMemoryInfo.MemoryLoadBytes, gcMemoryInfo.HighMemoryLoadThresholdBytes); return(true); // continue receiving gen 2 GC callbacks }
private static long GetDefaultMaxPoolSizeBytes() { #if NETCOREAPP3_1_OR_GREATER // On 64 bit .NET Core 3.1+, set the pool size to a portion of the total available memory. // There is a bug in GC.GetGCMemoryInfo() on .NET 5 + 32 bit, making TotalAvailableMemoryBytes unreliable: // https://github.com/dotnet/runtime/issues/55126#issuecomment-876779327 if (Environment.Is64BitProcess || !RuntimeInformation.FrameworkDescription.StartsWith(".NET 5.0")) { GCMemoryInfo info = GC.GetGCMemoryInfo(); return(info.TotalAvailableMemoryBytes / 8); } #endif // Stick to a conservative value of 128 Megabytes on other platforms and 32 bit .NET 5.0: return(128 * OneMegabyte); }
private static MemoryPressure GetMemoryPressure() { const double HighPressureThreshold = .90; // Percent of GC memory pressure threshold we consider "high" const double MediumPressureThreshold = .70; // Percent of GC memory pressure threshold we consider "medium" GCMemoryInfo memoryInfo = GC.GetGCMemoryInfo(); if (memoryInfo.MemoryLoadBytes >= memoryInfo.HighMemoryLoadThresholdBytes * HighPressureThreshold) { return(MemoryPressure.High); } else if (memoryInfo.MemoryLoadBytes >= memoryInfo.HighMemoryLoadThresholdBytes * MediumPressureThreshold) { return(MemoryPressure.Medium); } return(MemoryPressure.Low); }
public static void GetGCMemoryInfo() { RemoteExecutor.Invoke(() => { // Allows to update the value returned by GC.GetGCMemoryInfo GC.Collect(); GCMemoryInfo memoryInfo1 = GC.GetGCMemoryInfo(); Assert.InRange(memoryInfo1.HighMemoryLoadThresholdBytes, 1, long.MaxValue); Assert.InRange(memoryInfo1.MemoryLoadBytes, 1, long.MaxValue); Assert.InRange(memoryInfo1.TotalAvailableMemoryBytes, 1, long.MaxValue); Assert.InRange(memoryInfo1.HeapSizeBytes, 1, long.MaxValue); Assert.InRange(memoryInfo1.FragmentedBytes, 0, long.MaxValue); GCHandle[] gch = new GCHandle[64 * 1024]; for (int i = 0; i < gch.Length * 2; ++i) { byte[] arr = new byte[64]; if (i % 2 == 0) { gch[i / 2] = GCHandle.Alloc(arr, GCHandleType.Pinned); } } // Allows to update the value returned by GC.GetGCMemoryInfo GC.Collect(); GCMemoryInfo memoryInfo2 = GC.GetGCMemoryInfo(); Assert.Equal(memoryInfo2.HighMemoryLoadThresholdBytes, memoryInfo1.HighMemoryLoadThresholdBytes); Assert.InRange(memoryInfo2.MemoryLoadBytes, memoryInfo1.MemoryLoadBytes, long.MaxValue); Assert.Equal(memoryInfo2.TotalAvailableMemoryBytes, memoryInfo1.TotalAvailableMemoryBytes); Assert.InRange(memoryInfo2.HeapSizeBytes, memoryInfo1.HeapSizeBytes + 1, long.MaxValue); Assert.InRange(memoryInfo2.FragmentedBytes, memoryInfo1.FragmentedBytes + 1, long.MaxValue); }).Dispose(); }
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArmProcess))] // [ActiveIssue(37378)] public static void GetGCMemoryInfo() { RemoteExecutor.Invoke(() => { // Allows to update the value returned by GC.GetGCMemoryInfo GC.Collect(); GCMemoryInfo memoryInfo1 = GC.GetGCMemoryInfo(); Assert.InRange(memoryInfo1.HighMemoryLoadThresholdBytes, 1, long.MaxValue); Assert.InRange(memoryInfo1.MemoryLoadBytes, 1, long.MaxValue); Assert.InRange(memoryInfo1.TotalAvailableMemoryBytes, 1, long.MaxValue); Assert.InRange(memoryInfo1.HeapSizeBytes, 1, long.MaxValue); Assert.InRange(memoryInfo1.FragmentedBytes, 0, long.MaxValue); GCHandle[] gch = new GCHandle[64 * 1024]; for (int i = 0; i < gch.Length * 2; ++i) { byte[] arr = new byte[64]; if (i % 2 == 0) { gch[i / 2] = GCHandle.Alloc(arr, GCHandleType.Pinned); } } // Allows to update the value returned by GC.GetGCMemoryInfo GC.Collect(); GCMemoryInfo memoryInfo2 = GC.GetGCMemoryInfo(); string scenario = null; try { scenario = nameof(memoryInfo2.HighMemoryLoadThresholdBytes); Assert.Equal(memoryInfo2.HighMemoryLoadThresholdBytes, memoryInfo1.HighMemoryLoadThresholdBytes); // Even though we have allocated, the overall load may decrease or increase depending what other processes are doing. // It cannot go above total available though. scenario = nameof(memoryInfo2.MemoryLoadBytes); Assert.InRange(memoryInfo2.MemoryLoadBytes, 1, memoryInfo1.TotalAvailableMemoryBytes); scenario = nameof(memoryInfo2.TotalAvailableMemoryBytes); Assert.Equal(memoryInfo2.TotalAvailableMemoryBytes, memoryInfo1.TotalAvailableMemoryBytes); scenario = nameof(memoryInfo2.HeapSizeBytes); Assert.InRange(memoryInfo2.HeapSizeBytes, memoryInfo1.HeapSizeBytes + 1, long.MaxValue); scenario = nameof(memoryInfo2.FragmentedBytes); Assert.InRange(memoryInfo2.FragmentedBytes, memoryInfo1.FragmentedBytes + 1, long.MaxValue); scenario = null; } finally { if (scenario != null) { System.Console.WriteLine("FAILED: " + scenario); } } }).Dispose(); }
public static int Main() { // We will keep executing the test in case of a failure to see if we have multiple failures. bool isTestSucceeded = true; try { GCMemoryInfo memoryInfoInvalid = GC.GetGCMemoryInfo((GCKind)(-1)); } catch (Exception e) { if (e is ArgumentOutOfRangeException) { Console.WriteLine("caught arg exception as expected: {0}", e); } else { isTestSucceeded = false; } } while (GC.CollectionCount(0) == 0) { MakeTemporarySOHAllocations(); } if (!PrintGCMemoryInfo(GCKind.Ephemeral)) { isTestSucceeded = false; } GCMemoryInfo memoryInfo = GC.GetGCMemoryInfo(GCKind.Ephemeral); if (memoryInfo.GenerationInfo[0].SizeBeforeBytes < memoryInfo.GenerationInfo[0].SizeAfterBytes) { Console.WriteLine("Allocated only temp objects yet gen0 size didn't shrink! {0}->{1}", memoryInfo.GenerationInfo[0].SizeBeforeBytes, memoryInfo.GenerationInfo[0].SizeAfterBytes); isTestSucceeded = false; } List <byte[]> listByteArray = new List <byte[]>(); listByteArray.Add(new byte[3 * 1024 * 1024]); listByteArray.Add(new byte[4 * 1024 * 1024]); GC.Collect(); GC.Collect(); GCMemoryInfo memoryInfoLastNGC2 = GC.GetGCMemoryInfo(GCKind.FullBlocking); GCMemoryInfo memoryInfoLastAnyGC = GC.GetGCMemoryInfo(); if (memoryInfoLastNGC2.Index != memoryInfoLastAnyGC.Index) { Console.WriteLine("FAILED: last GC#{0} should be NGC2 but was not", memoryInfoLastAnyGC.Index); isTestSucceeded = false; } object obj = MakeLongLivedSOHAllocations(); GC.Collect(1); GC.Collect(); GC.Collect(2, GCCollectionMode.Default, false); if (!PrintGCMemoryInfo(GCKind.Any)) { isTestSucceeded = false; } long lastNGC2Index = GC.GetGCMemoryInfo(GCKind.FullBlocking).Index; long lastEphemeralIndex = GC.GetGCMemoryInfo(GCKind.Ephemeral).Index; GC.Collect(); if (!PrintGCMemoryInfo(GCKind.Any)) { isTestSucceeded = false; } GC.Collect(2, GCCollectionMode.Default, false); if (!PrintGCMemoryInfo(GCKind.Any)) { isTestSucceeded = false; } if (!PrintGCMemoryInfo(GCKind.FullBlocking)) { isTestSucceeded = false; } if (!PrintGCMemoryInfo(GCKind.Background)) { isTestSucceeded = false; } if (!PrintGCMemoryInfo(GCKind.Ephemeral)) { isTestSucceeded = false; } long currentNGC2Index = GC.GetGCMemoryInfo(GCKind.FullBlocking).Index; long currentEphemeralIndex = GC.GetGCMemoryInfo(GCKind.Ephemeral).Index; if (lastNGC2Index >= currentNGC2Index) { Console.WriteLine("FAILED: We did an additional NGC2, yet last NGC2 index is {0} and current is {1}", lastNGC2Index, currentNGC2Index); isTestSucceeded = false; } if (lastEphemeralIndex != currentEphemeralIndex) { Console.WriteLine("FAILED: No ephemeral GCs happened so far, yet last eph index is {0} and current is {1}", lastEphemeralIndex, currentEphemeralIndex); isTestSucceeded = false; } Console.WriteLine("listByteArray has {0} elements, obj is of type {1}", listByteArray.Count, obj.GetType()); Console.WriteLine("test {0}", (isTestSucceeded ? "succeeded" : "failed")); return(isTestSucceeded ? 100 : 1); }
public static double GetAvailableMemoryGiB() { GCMemoryInfo gcMemoryInfo = GC.GetGCMemoryInfo(); return(FromBytesToGiB(gcMemoryInfo.TotalAvailableMemoryBytes - gcMemoryInfo.MemoryLoadBytes)); }
private Block(int id, GCMemoryInfo i = default) => _id = id;
private bool ConcurrentPurge() { const int LowAfterMilliseconds = 180 * 1000; // Trim after 60 seconds for low pressure. const int MediumAfterMilliseconds = 90 * 1000; // Trim after 60 seconds for medium pressure. const double HighPressureThreshold = .90; // Percent of GC memory pressure threshold we consider "high". const double MediumPressureThreshold = .70; // Percent of GC memory pressure threshold we consider "medium". int currentMilliseconds = Environment.TickCount; for (int j = 0; j < PurgeAttempts; j++) { // The callback was called before finishing the previous purge. if ((state & IS_PURGING) != 0) { return(true); } if (state == IS_DISPOSED_OR_DISPOSING) { return(false); } MassiveWriteBegin(); { if (state == IS_DISPOSED_OR_DISPOSING) { WriteEnd(); return(false); } if (holdersCount == 0) { WriteEnd(); return(true); } int trimMilliseconds; #if NET5_0_OR_GREATER GCMemoryInfo memoryInfo = GC.GetGCMemoryInfo(); if (memoryInfo.MemoryLoadBytes >= memoryInfo.HighMemoryLoadThresholdBytes * HighPressureThreshold) { trimMilliseconds = 0; } else if (memoryInfo.MemoryLoadBytes >= memoryInfo.HighMemoryLoadThresholdBytes * MediumPressureThreshold) { trimMilliseconds = MediumAfterMilliseconds; } else { trimMilliseconds = LowAfterMilliseconds; } #else trimMilliseconds = 0; #endif if (millisecondsTimeStamp == 0) { millisecondsTimeStamp = currentMilliseconds; } if ((currentMilliseconds - millisecondsTimeStamp) <= trimMilliseconds) { WriteEnd(); return(true); } state = IS_PURGING; Debug.Assert(holders is not null, "Impossible state, since holders initialization happens at the same time AutoPurger is instantiated."); if (holdersCount > 1) { purgingIndex += (int)(Parallel.For(0, holdersCount, options ??= new(), autoPurgeAction ??= new Action <int, ParallelLoopState>((index, loop) => { if (loop.ShouldExitCurrentIteration) { return; } if ((state & IS_CANCELATION_REQUESTED) != 0) { loop.Stop(); } Utils.ExpectAssignableType <InvokersHolder>(holders[(purgingIndex + index) % holdersCount]).Purge(); })).LowestBreakIteration ?? 0); } else if (holdersCount == 1) { Utils.ExpectAssignableType <InvokersHolder>(holders[0]).Purge(); } bool isCancelationRequested = (state & IS_CANCELATION_REQUESTED) != 0; int holdersCountOld = holdersCount; int holdersCount_ = holdersCountOld; InvariantObject[] holders_ = holders; // TODO: This loop could actually be done without locking the whole event manager, // as long as the `holders` array is locked. for (int i = 0; i < holdersCount_; i++) { InvokersHolder holder = Utils.ExpectAssignableType <InvokersHolder>(holders_[i].Value); if (holder.RemoveIfEmpty()) { holdersPerType.Remove(holder.GetType()); managersPerType[holder.GetEventType()].Remove(holder); while (true) { if (--holdersCount_ == i) { goto end; } holder = Utils.ExpectAssignableType <InvokersHolder>(holders_[holdersCount_].Value); if (!holder.RemoveIfEmpty()) { break; } holdersPerType.Remove(holder.GetType()); managersPerType[holder.GetEventType()].Remove(holder); } holders_[i] = holders_[i + 1]; } } end: if (!ArrayUtils.TryShrink(ref holders_, holdersCount_) && holdersCount_ != holdersCountOld) { Array.Clear(holders_, holdersCount_, holdersCountOld - holdersCount_); } holders = holders_; holdersCount = holdersCount_; Lock(ref stateLock); { state = 0; } Unlock(ref stateLock); WriteEnd(); if (isCancelationRequested && Thread.Yield()) { continue; } return(true); } } Debug.Fail("Impossible state."); return(true); }