com.alicizax.unity.framework/Runtime/Debugger/DebuggerComponent.ReferencePoolInformationWindow.cs

154 lines
7.1 KiB
C#
Raw Normal View History

using System;
2025-09-05 19:46:30 +08:00
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
2025-09-05 19:46:30 +08:00
namespace AlicizaX.Debugger.Runtime
{
public sealed partial class DebuggerComponent
{
private sealed class ReferencePoolInformationWindow : PollingDebuggerWindowBase
2025-09-05 19:46:30 +08:00
{
private readonly Dictionary<string, List<MemoryPoolInfo>> m_ReferencePoolInfos = new Dictionary<string, List<MemoryPoolInfo>>(StringComparer.Ordinal);
private readonly Comparison<MemoryPoolInfo> m_NormalClassNameComparer = NormalClassNameComparer;
private readonly Comparison<MemoryPoolInfo> m_FullClassNameComparer = FullClassNameComparer;
private bool m_ShowFullClassName;
private Toggle showFullClassNameToggle;
2025-09-05 19:46:30 +08:00
protected override void BuildWindow(VisualElement root)
2025-09-05 19:46:30 +08:00
{
2026-04-21 14:24:36 +08:00
float scale = DebuggerComponent.Instance != null ? DebuggerComponent.Instance.GetUiScale() : 1f;
// ---- Overview Section ----
VisualElement overview = CreateSection("Memory Pool Overview", out VisualElement overviewCard);
overviewCard.Add(CreateRow("Enable Strict Check", MemoryPool.EnableStrictCheck.ToString()));
2026-04-21 14:24:36 +08:00
overviewCard.Add(CreateRow("Pool Type Count", MemoryPool.Count.ToString()));
// 统计总缓存对象数和总数组容量
MemoryPoolInfo[] allInfos = MemoryPool.GetAllMemoryPoolInfos();
int totalUnused = 0;
int totalUsing = 0;
int totalArrayLen = 0;
foreach (var info in allInfos)
{
totalUnused += info.UnusedCount;
totalUsing += info.UsingCount;
totalArrayLen += info.PoolArrayLength;
}
overviewCard.Add(CreateRow("Total Cached Objects", totalUnused.ToString()));
overviewCard.Add(CreateRow("Total In Use", totalUsing.ToString()));
overviewCard.Add(CreateRow("Total Array Capacity", totalArrayLen.ToString()));
showFullClassNameToggle = CreateConsoleFilterToggle("Show Full ClassName", m_ShowFullClassName, DebuggerTheme.PrimaryText, value => m_ShowFullClassName = value);
overviewCard.Add(showFullClassNameToggle);
2026-04-21 14:24:36 +08:00
// ---- 操作按钮 ----
VisualElement buttonRow = new VisualElement();
buttonRow.style.flexDirection = FlexDirection.Row;
buttonRow.style.marginTop = 8f * scale;
buttonRow.Add(CreateActionButton("Clear All Pools", () =>
{
MemoryPoolRegistry.ClearAll();
Rebuild();
}, DebuggerTheme.Danger));
overviewCard.Add(buttonRow);
root.Add(overview);
2025-09-05 19:46:30 +08:00
2026-04-21 14:24:36 +08:00
// ---- 按 Assembly 分组 ----
2025-09-05 19:46:30 +08:00
m_ReferencePoolInfos.Clear();
2026-04-21 14:24:36 +08:00
foreach (MemoryPoolInfo info in allInfos)
2025-09-05 19:46:30 +08:00
{
2026-04-21 14:24:36 +08:00
string assemblyName = info.Type.Assembly.GetName().Name;
if (!m_ReferencePoolInfos.TryGetValue(assemblyName, out List<MemoryPoolInfo> results))
2025-09-05 19:46:30 +08:00
{
results = new List<MemoryPoolInfo>();
m_ReferencePoolInfos.Add(assemblyName, results);
}
2026-04-21 14:24:36 +08:00
results.Add(info);
2025-09-05 19:46:30 +08:00
}
2026-04-21 14:24:36 +08:00
foreach (KeyValuePair<string, List<MemoryPoolInfo>> assemblyInfo in m_ReferencePoolInfos)
2025-09-05 19:46:30 +08:00
{
2026-04-21 14:24:36 +08:00
assemblyInfo.Value.Sort(m_ShowFullClassName ? m_FullClassNameComparer : m_NormalClassNameComparer);
VisualElement section = CreateSection(Utility.Text.Format("Assembly: {0}", assemblyInfo.Key), out VisualElement card);
if (assemblyInfo.Value.Count <= 0)
2025-09-05 19:46:30 +08:00
{
2026-04-21 14:24:36 +08:00
card.Add(CreateRow("State", "Memory Pool is Empty ..."));
}
else
{
2026-04-21 14:24:36 +08:00
for (int i = 0; i < assemblyInfo.Value.Count; i++)
2025-09-05 19:46:30 +08:00
{
2026-04-21 14:24:36 +08:00
card.Add(CreatePoolInfoItem(assemblyInfo.Value[i], m_ShowFullClassName, scale));
2025-09-05 19:46:30 +08:00
}
}
root.Add(section);
2025-09-05 19:46:30 +08:00
}
}
private static int NormalClassNameComparer(MemoryPoolInfo a, MemoryPoolInfo b)
{
return a.Type.Name.CompareTo(b.Type.Name);
}
private static int FullClassNameComparer(MemoryPoolInfo a, MemoryPoolInfo b)
{
return a.Type.FullName.CompareTo(b.Type.FullName);
}
2026-04-21 14:24:36 +08:00
private static VisualElement CreatePoolInfoItem(MemoryPoolInfo info, bool showFullName, float scale)
{
VisualElement item = CreateCard();
item.style.marginBottom = 8f * scale;
item.style.backgroundColor = DebuggerTheme.PanelSurfaceAlt;
2026-04-21 14:24:36 +08:00
string title = showFullName ? info.Type.FullName : info.Type.Name;
Label titleLabel = new Label(title ?? string.Empty);
titleLabel.style.color = DebuggerTheme.PrimaryText;
titleLabel.style.fontSize = 16f * scale;
titleLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
titleLabel.style.whiteSpace = WhiteSpace.Normal;
titleLabel.style.marginBottom = 6f * scale;
2026-04-21 14:24:36 +08:00
item.Add(titleLabel);
2026-04-21 14:24:36 +08:00
// 基础统计
string stats = Utility.Text.Format(
"Unused {0} | Using {1} | Acquire {2} | Release {3} | Created {4}",
info.UnusedCount, info.UsingCount,
info.AcquireCount, info.ReleaseCount,
info.CreateCount);
Label statsLabel = new Label(stats);
statsLabel.style.color = DebuggerTheme.SecondaryText;
statsLabel.style.fontSize = 14f * scale;
statsLabel.style.whiteSpace = WhiteSpace.Normal;
statsLabel.style.marginBottom = 4f * scale;
item.Add(statsLabel);
2026-04-21 14:24:36 +08:00
// 回收策略状态
string recycleStatus = Utility.Text.Format(
"HighWater {0} | MaxCap {1} | Idle {2}f | Array {3}",
info.HighWaterMark, info.MaxCapacity,
info.IdleFrames, info.PoolArrayLength);
Label recycleLabel = new Label(recycleStatus);
recycleLabel.style.fontSize = 13f * scale;
recycleLabel.style.whiteSpace = WhiteSpace.Normal;
// 根据空闲帧数着色:接近回收阈值时变色
if (info.IdleFrames >= 300)
recycleLabel.style.color = DebuggerTheme.Warning;
else if (info.IdleFrames >= 200)
recycleLabel.style.color = new Color(0.9f, 0.7f, 0.3f);
else
recycleLabel.style.color = DebuggerTheme.SecondaryText;
item.Add(recycleLabel);
return item;
}
2025-09-05 19:46:30 +08:00
}
}
}