2025-09-05 19:46:30 +08:00
using System ;
using System.Collections.Generic ;
using UnityEngine ;
using UnityEngine.Profiling ;
2026-04-21 13:01:55 +08:00
using UnityEngine.UIElements ;
2025-09-05 19:46:30 +08:00
namespace AlicizaX.Debugger.Runtime
{
public sealed partial class DebuggerComponent
{
private sealed partial class RuntimeMemoryInformationWindow < T > : ScrollableDebuggerWindowBase where T : UnityEngine . Object
{
private const int ShowSampleCount = 300 ;
private readonly List < Sample > m_Samples = new List < Sample > ( ) ;
private readonly Comparison < Sample > m_SampleComparer = SampleComparer ;
private DateTime m_SampleTime = DateTime . MinValue ;
2026-04-21 13:01:55 +08:00
private long m_SampleSize ;
private long m_DuplicateSampleSize ;
private int m_DuplicateSimpleCount ;
2025-09-05 19:46:30 +08:00
2026-04-21 13:01:55 +08:00
protected override void BuildWindow ( VisualElement root )
2025-09-05 19:46:30 +08:00
{
string typeName = typeof ( T ) . Name ;
2026-04-21 13:01:55 +08:00
VisualElement actions = CreateSection ( "Actions" , out VisualElement actionCard ) ;
actionCard . Add ( CreateActionButton ( Utility . Text . Format ( "Take Sample for {0}" , typeName ) , TakeSample , DebuggerTheme . ButtonSurfaceActive ) ) ;
root . Add ( actions ) ;
2025-09-05 19:46:30 +08:00
2026-04-21 13:01:55 +08:00
VisualElement section = CreateSection ( Utility . Text . Format ( "{0} Runtime Memory" , typeName ) , out VisualElement card ) ;
if ( m_SampleTime < = DateTime . MinValue )
{
card . Add ( CreateRow ( "State" , Utility . Text . Format ( "Please take sample for {0} first." , typeName ) ) ) ;
}
else
{
if ( m_DuplicateSimpleCount > 0 )
2025-09-05 19:46:30 +08:00
{
2026-04-21 13:01:55 +08:00
card . Add ( CreateRow ( "Summary" , Utility . Text . Format ( "{0} {1}s ({2}) obtained at {3:yyyy-MM-dd HH:mm:ss}, while {4} {1}s ({5}) might be duplicated." , m_Samples . Count , typeName , GetByteLengthString ( m_SampleSize ) , m_SampleTime . ToLocalTime ( ) , m_DuplicateSimpleCount , GetByteLengthString ( m_DuplicateSampleSize ) ) ) ) ;
2025-09-05 19:46:30 +08:00
}
else
{
2026-04-21 13:01:55 +08:00
card . Add ( CreateRow ( "Summary" , Utility . Text . Format ( "{0} {1}s ({2}) obtained at {3:yyyy-MM-dd HH:mm:ss}." , m_Samples . Count , typeName , GetByteLengthString ( m_SampleSize ) , m_SampleTime . ToLocalTime ( ) ) ) ) ;
}
2025-09-05 19:46:30 +08:00
2026-04-21 13:01:55 +08:00
int count = Mathf . Min ( ShowSampleCount , m_Samples . Count ) ;
for ( int i = 0 ; i < count ; i + + )
{
Sample sample = m_Samples [ i ] ;
string title = sample . Highlight ? Utility . Text . Format ( "[Possible Duplicate] {0}" , sample . Name ) : sample . Name ;
string content = Utility . Text . Format ( "{0} | {1}" , sample . Type , GetByteLengthString ( sample . Size ) ) ;
card . Add ( CreateRow ( title , content ) ) ;
2025-09-05 19:46:30 +08:00
}
}
2026-04-21 13:01:55 +08:00
root . Add ( section ) ;
2025-09-05 19:46:30 +08:00
}
private void TakeSample ( )
{
m_SampleTime = DateTime . UtcNow ;
m_SampleSize = 0L ;
m_DuplicateSampleSize = 0L ;
m_DuplicateSimpleCount = 0 ;
m_Samples . Clear ( ) ;
T [ ] samples = Resources . FindObjectsOfTypeAll < T > ( ) ;
for ( int i = 0 ; i < samples . Length ; i + + )
{
2026-04-21 13:01:55 +08:00
long sampleSize = Profiler . GetRuntimeMemorySizeLong ( samples [ i ] ) ;
2025-09-05 19:46:30 +08:00
m_SampleSize + = sampleSize ;
m_Samples . Add ( new Sample ( samples [ i ] . name , samples [ i ] . GetType ( ) . Name , sampleSize ) ) ;
}
m_Samples . Sort ( m_SampleComparer ) ;
for ( int i = 1 ; i < m_Samples . Count ; i + + )
{
if ( m_Samples [ i ] . Name = = m_Samples [ i - 1 ] . Name & & m_Samples [ i ] . Type = = m_Samples [ i - 1 ] . Type & & m_Samples [ i ] . Size = = m_Samples [ i - 1 ] . Size )
{
m_Samples [ i ] . Highlight = true ;
m_DuplicateSampleSize + = m_Samples [ i ] . Size ;
m_DuplicateSimpleCount + + ;
}
}
2026-04-21 13:01:55 +08:00
Rebuild ( ) ;
2025-09-05 19:46:30 +08:00
}
private static int SampleComparer ( Sample a , Sample b )
{
int result = b . Size . CompareTo ( a . Size ) ;
if ( result ! = 0 )
{
return result ;
}
result = a . Type . CompareTo ( b . Type ) ;
if ( result ! = 0 )
{
return result ;
}
return a . Name . CompareTo ( b . Name ) ;
}
}
}
}