2026-04-21 14:24:36 +08:00
using AlicizaX ;
2025-10-11 15:18:09 +08:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Text ;
using UnityEditor ;
using UnityEngine ;
namespace AlicizaX.Editor
{
[CustomEditor(typeof(MemoryPoolSetting))]
internal sealed class MemoryPoolComponentInspector : GameFrameworkInspector
{
private readonly Dictionary < string , List < MemoryPoolInfo > > m_ReferencePoolInfos = new Dictionary < string , List < MemoryPoolInfo > > ( StringComparer . Ordinal ) ;
private readonly HashSet < string > m_OpenedItems = new HashSet < string > ( ) ;
private SerializedProperty m_EnableStrictCheck = null ;
private bool m_ShowFullClassName = false ;
public override void OnInspectorGUI ( )
{
base . OnInspectorGUI ( ) ;
serializedObject . Update ( ) ;
MemoryPoolSetting t = ( MemoryPoolSetting ) target ;
if ( EditorApplication . isPlaying & & IsPrefabInHierarchy ( t . gameObject ) )
{
bool enableStrictCheck = EditorGUILayout . Toggle ( "Enable Strict Check" , t . EnableStrictCheck ) ;
if ( enableStrictCheck ! = t . EnableStrictCheck )
{
t . EnableStrictCheck = enableStrictCheck ;
}
2026-04-21 14:24:36 +08:00
EditorGUILayout . LabelField ( "Memory Pool Count" , MemoryPool . Count . ToString ( ) ) ;
2025-10-11 15:18:09 +08:00
m_ShowFullClassName = EditorGUILayout . Toggle ( "Show Full Class Name" , m_ShowFullClassName ) ;
2026-04-21 14:24:36 +08:00
// 全局统计
2025-10-11 15:18:09 +08:00
MemoryPoolInfo [ ] referencePoolInfos = MemoryPool . GetAllMemoryPoolInfos ( ) ;
2026-04-21 14:24:36 +08:00
int totalUnused = 0 , totalUsing = 0 , totalArrayLen = 0 ;
foreach ( var info in referencePoolInfos )
{
totalUnused + = info . UnusedCount ;
totalUsing + = info . UsingCount ;
totalArrayLen + = info . PoolArrayLength ;
}
EditorGUILayout . LabelField ( "Total Cached" , totalUnused . ToString ( ) ) ;
EditorGUILayout . LabelField ( "Total In Use" , totalUsing . ToString ( ) ) ;
EditorGUILayout . LabelField ( "Total Array Capacity" , totalArrayLen . ToString ( ) ) ;
EditorGUILayout . Space ( ) ;
// 全局操作按钮
EditorGUILayout . BeginHorizontal ( ) ;
if ( GUILayout . Button ( "Clear All Pools" ) )
{
MemoryPoolRegistry . ClearAll ( ) ;
}
EditorGUILayout . EndHorizontal ( ) ;
EditorGUILayout . Space ( ) ;
// 按 Assembly 分组
m_ReferencePoolInfos . Clear ( ) ;
2025-10-11 15:18:09 +08:00
foreach ( MemoryPoolInfo referencePoolInfo in referencePoolInfos )
{
string assemblyName = referencePoolInfo . Type . Assembly . GetName ( ) . Name ;
2026-04-21 14:24:36 +08:00
if ( ! m_ReferencePoolInfos . TryGetValue ( assemblyName , out List < MemoryPoolInfo > results ) )
2025-10-11 15:18:09 +08:00
{
results = new List < MemoryPoolInfo > ( ) ;
m_ReferencePoolInfos . Add ( assemblyName , results ) ;
}
results . Add ( referencePoolInfo ) ;
}
foreach ( KeyValuePair < string , List < MemoryPoolInfo > > assemblyReferencePoolInfo in m_ReferencePoolInfos )
{
bool lastState = m_OpenedItems . Contains ( assemblyReferencePoolInfo . Key ) ;
bool currentState = EditorGUILayout . Foldout ( lastState , assemblyReferencePoolInfo . Key ) ;
if ( currentState ! = lastState )
{
if ( currentState )
m_OpenedItems . Add ( assemblyReferencePoolInfo . Key ) ;
else
m_OpenedItems . Remove ( assemblyReferencePoolInfo . Key ) ;
}
if ( currentState )
{
EditorGUILayout . BeginVertical ( "box" ) ;
{
2026-04-21 14:24:36 +08:00
var label = "Unused\tUsing\tAcquire\tRelease\tCreated\tHiWater\tMaxCap\tIdle\tArrLen" ;
2025-10-11 15:18:09 +08:00
EditorGUILayout . LabelField ( m_ShowFullClassName ? "Full Class Name" : "Class Name" , label ) ;
assemblyReferencePoolInfo . Value . Sort ( Comparison ) ;
foreach ( MemoryPoolInfo referencePoolInfo in assemblyReferencePoolInfo . Value )
{
DrawReferencePoolInfo ( referencePoolInfo ) ;
}
if ( GUILayout . Button ( "Export CSV Data" ) )
{
2026-04-21 14:24:36 +08:00
string exportFileName = EditorUtility . SaveFilePanel ( "Export CSV Data" , string . Empty , Utility . Text . Format ( "Memory Pool Data - {0}.csv" , assemblyReferencePoolInfo . Key ) , string . Empty ) ;
2025-10-11 15:18:09 +08:00
if ( ! string . IsNullOrEmpty ( exportFileName ) )
{
try
{
int index = 0 ;
string [ ] data = new string [ assemblyReferencePoolInfo . Value . Count + 1 ] ;
2026-04-21 14:24:36 +08:00
data [ index + + ] = "Class Name,Full Class Name,Unused,Using,Acquire,Release,Created,HighWaterMark,MaxCapacity,IdleFrames,ArrayLength" ;
foreach ( MemoryPoolInfo info in assemblyReferencePoolInfo . Value )
2025-10-11 15:18:09 +08:00
{
2026-04-21 14:24:36 +08:00
data [ index + + ] = Utility . Text . Format ( "{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10}" ,
info . Type . Name , info . Type . FullName ,
info . UnusedCount , info . UsingCount ,
info . AcquireCount , info . ReleaseCount ,
info . CreateCount , info . HighWaterMark ,
info . MaxCapacity , info . IdleFrames , info . PoolArrayLength ) ;
2025-10-11 15:18:09 +08:00
}
File . WriteAllLines ( exportFileName , data , Encoding . UTF8 ) ;
2026-04-21 14:24:36 +08:00
Debug . Log ( Utility . Text . Format ( "Export memory pool CSV data to '{0}' success." , exportFileName ) ) ;
2025-10-11 15:18:09 +08:00
}
catch ( Exception exception )
{
2026-04-21 14:24:36 +08:00
Debug . LogError ( Utility . Text . Format ( "Export memory pool CSV data to '{0}' failure, exception is '{1}'." , exportFileName , exception ) ) ;
2025-10-11 15:18:09 +08:00
}
}
}
}
EditorGUILayout . EndVertical ( ) ;
EditorGUILayout . Separator ( ) ;
}
}
}
else
{
EditorGUILayout . PropertyField ( m_EnableStrictCheck ) ;
}
serializedObject . ApplyModifiedProperties ( ) ;
Repaint ( ) ;
}
private void OnEnable ( )
{
m_EnableStrictCheck = serializedObject . FindProperty ( "m_EnableStrictCheck" ) ;
}
2026-04-21 14:24:36 +08:00
private void DrawReferencePoolInfo ( MemoryPoolInfo info )
2025-10-11 15:18:09 +08:00
{
2026-04-21 14:24:36 +08:00
string name = m_ShowFullClassName ? info . Type . FullName : info . Type . Name ;
string values = Utility . Text . Format ( "{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}" ,
info . UnusedCount , info . UsingCount ,
info . AcquireCount , info . ReleaseCount ,
info . CreateCount , info . HighWaterMark ,
info . MaxCapacity , info . IdleFrames , info . PoolArrayLength ) ;
EditorGUILayout . LabelField ( name , values ) ;
2025-10-11 15:18:09 +08:00
}
private int Comparison ( MemoryPoolInfo a , MemoryPoolInfo b )
{
if ( m_ShowFullClassName )
return a . Type . FullName . CompareTo ( b . Type . FullName ) ;
else
return a . Type . Name . CompareTo ( b . Type . Name ) ;
}
}
}