A game framework written with osu! in mind.
at master 65 lines 2.5 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using osu.Framework.Allocation; 6using osu.Framework.Statistics; 7 8namespace osu.Framework.Platform 9{ 10 /// <summary> 11 /// Track native memory allocations via <see cref="GlobalStatistics"/>. 12 /// Also adds memory pressure automatically. 13 /// </summary> 14 public static class NativeMemoryTracker 15 { 16 /// <summary> 17 /// Add new tracked native memory. 18 /// </summary> 19 /// <param name="source">The object responsible for this allocation.</param> 20 /// <param name="amount">The number of bytes allocated.</param> 21 /// <returns>A lease which should be disposed when memory is released.</returns> 22 public static NativeMemoryLease AddMemory(object source, long amount) 23 { 24 getStatistic(source).Value += amount; 25 GC.AddMemoryPressure(amount); 26 27 return new NativeMemoryLease((source, amount), sender => removeMemory(sender.source, sender.amount)); 28 } 29 30 /// <summary> 31 /// Remove previously tracked native memory. 32 /// </summary> 33 /// <param name="source">The object responsible for this allocation.</param> 34 /// <param name="amount">The number of bytes allocated.</param> 35 private static void removeMemory(object source, long amount) 36 { 37 getStatistic(source).Value -= amount; 38 GC.RemoveMemoryPressure(amount); 39 } 40 41 private static GlobalStatistic<long> getStatistic(object source) => GlobalStatistics.Get<long>("Native", source.GetType().Name); 42 43 /// <summary> 44 /// A leased on a native memory allocation. Should be disposed when the associated memory is freed. 45 /// </summary> 46 public class NativeMemoryLease : InvokeOnDisposal<(object source, long amount)> 47 { 48 internal NativeMemoryLease((object source, long amount) sender, Action<(object source, long amount)> action) 49 : base(sender, action) 50 { 51 } 52 53 private bool isDisposed; 54 55 public override void Dispose() 56 { 57 if (isDisposed) 58 throw new ObjectDisposedException(ToString(), $"{nameof(NativeMemoryLease)} should not be disposed more than once"); 59 60 base.Dispose(); 61 isDisposed = true; 62 } 63 } 64 } 65}