From 797619aeceb3457475192ed051a0847a07e67a1d Mon Sep 17 00:00:00 2001 From: YHH <359807859@qq.com> Date: Tue, 17 Jun 2025 07:35:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B1=A0=E5=88=A9=E7=94=A8?= =?UTF-8?q?=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../source/panels/debug/index.ts | 134 ++++++- .../static/style/debug/index.css | 343 +++++++++++++++++- .../static/template/debug/index.html | 92 ++++- src/ECS/Core/ComponentPool.ts | 34 ++ src/Types/index.ts | 6 + src/Utils/DebugReporter.ts | 115 ++++-- 6 files changed, 681 insertions(+), 43 deletions(-) diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/panels/debug/index.ts b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/panels/debug/index.ts index 23526042..096fa00b 100644 --- a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/panels/debug/index.ts +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/source/panels/debug/index.ts @@ -38,6 +38,8 @@ interface DetailedDebugInfo { minFrameTime: number; maxFrameTime: number; frameTimeHistory: number[]; + engineFrameTime: number; + ecsPercentage: number; }; // 内存信息 @@ -100,6 +102,7 @@ interface DetailedDebugInfo { memoryUsage: number; updateOrder: number; enabled: boolean; + percentage: number; }>; }; @@ -254,6 +257,16 @@ class ECSDebugServer { private transformToDetailedDebugInfo(instance: GameInstance, rawData: any): DetailedDebugInfo { const uptime = (Date.now() - instance.connectTime) / 1000; + // 计算系统性能数据,包括ECS占比 + const systemBreakdown = rawData.performance?.systemBreakdown || []; + const systemPerformance = rawData.performance?.systemPerformance || []; + + // 创建系统名称到占比的映射 + const systemPercentageMap = new Map(); + systemBreakdown.forEach((sys: any) => { + systemPercentageMap.set(sys.systemName, sys.percentage || 0); + }); + return { instanceId: instance.id, instanceName: instance.name, @@ -268,7 +281,9 @@ class ECSDebugServer { averageFrameTime: rawData.performance?.averageFrameTime || rawData.performance?.frameTime || 0, minFrameTime: rawData.performance?.minFrameTime || rawData.performance?.frameTime || 0, maxFrameTime: rawData.performance?.maxFrameTime || rawData.performance?.frameTime || 0, - frameTimeHistory: rawData.performance?.frameTimeHistory || [] + frameTimeHistory: rawData.performance?.frameTimeHistory || [], + engineFrameTime: rawData.performance?.engineFrameTime || 0, + ecsPercentage: rawData.performance?.ecsPercentage || 0 }, memory: { @@ -307,18 +322,24 @@ class ECSDebugServer { systems: { total: rawData.systems?.totalSystems || 0, - systemStats: (rawData.systems?.systemsInfo || []).map((sys: any) => ({ - name: sys.name, - type: sys.type || 'Unknown', - entityCount: sys.entityCount || 0, - averageExecutionTime: sys.executionTime || 0, - minExecutionTime: sys.minExecutionTime || sys.executionTime || 0, - maxExecutionTime: sys.maxExecutionTime || sys.executionTime || 0, - executionTimeHistory: sys.executionTimeHistory || [], - memoryUsage: sys.memoryUsage || 0, - updateOrder: sys.updateOrder || 0, - enabled: sys.enabled !== false - })) + systemStats: (rawData.systems?.systemsInfo || []).map((sys: any) => { + const systemName = sys.name; + const percentage = systemPercentageMap.get(systemName) || 0; + + return { + name: systemName, + type: sys.type || 'Unknown', + entityCount: sys.entityCount || 0, + averageExecutionTime: sys.executionTime || 0, + minExecutionTime: sys.minExecutionTime || sys.executionTime || 0, + maxExecutionTime: sys.maxExecutionTime || sys.executionTime || 0, + executionTimeHistory: sys.executionTimeHistory || [], + memoryUsage: sys.memoryUsage || 0, + updateOrder: sys.updateOrder || 0, + enabled: sys.enabled !== false, + percentage: percentage + }; + }) }, scenes: { @@ -348,7 +369,9 @@ const defaultDebugInfo: DetailedDebugInfo = { averageFrameTime: 0, minFrameTime: 0, maxFrameTime: 0, - frameTimeHistory: [] + frameTimeHistory: [], + engineFrameTime: 0, + ecsPercentage: 0 }, memory: { totalMemory: 0, @@ -425,6 +448,7 @@ module.exports = Editor.Panel.define({ const isAutoRefresh = ref(true); const refreshInterval = ref(100); const lastUpdateTime = ref(''); + const showComponentPoolHelp = ref(false); let intervalId: NodeJS.Timeout | null = null; let debugServer: ECSDebugServer | null = null; @@ -556,6 +580,84 @@ module.exports = Editor.Panel.define({ return 'critical'; }; + // 打开文档链接 + const openDocumentation = (section: string): void => { + const urls: Record = { + 'component-pool': 'https://github.com/esengine/ecs-framework/tree/master/docs/component-design-guide.md#1-对象池优化', + 'performance-optimization': 'https://github.com/esengine/ecs-framework/tree/master/docs/performance-optimization.md' + }; + + const url = urls[section]; + if (!url) return; + + try { + // 在Cocos Creator扩展环境中,直接使用Electron的shell模块 + const { shell } = require('electron'); + shell.openExternal(url); + } catch (error) { + console.error('无法打开链接:', error); + // 如果失败,复制到剪贴板 + copyUrlToClipboard(url); + } + }; + + // 复制链接到剪贴板的辅助函数 + const copyUrlToClipboard = (url: string): void => { + try { + // 尝试使用现代的剪贴板API + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(url).then(() => { + console.log(`文档链接已复制到剪贴板: ${url}`); + // 如果可能的话,显示用户友好的提示 + if (typeof alert !== 'undefined') { + alert(`文档链接已复制到剪贴板,请在浏览器中粘贴访问:\n${url}`); + } + }).catch(() => { + fallbackCopyText(url); + }); + } else { + fallbackCopyText(url); + } + } catch (error) { + fallbackCopyText(url); + } + }; + + // 备用的复制文本方法 + const fallbackCopyText = (text: string): void => { + try { + // 创建临时的文本区域 + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.position = 'fixed'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + const successful = document.execCommand('copy'); + document.body.removeChild(textArea); + + if (successful) { + console.log(`文档链接已复制到剪贴板: ${text}`); + if (typeof alert !== 'undefined') { + alert(`文档链接已复制到剪贴板,请在浏览器中粘贴访问:\n${text}`); + } + } else { + console.log(`请手动复制文档链接: ${text}`); + if (typeof alert !== 'undefined') { + alert(`请手动复制文档链接:\n${text}`); + } + } + } catch (error) { + console.log(`请手动访问文档: ${text}`); + if (typeof alert !== 'undefined') { + alert(`请手动访问文档:\n${text}`); + } + } + }; + // 组件挂载时初始化 onMounted(async () => { await initializeServer(); @@ -575,6 +677,7 @@ module.exports = Editor.Panel.define({ isAutoRefresh, refreshInterval, lastUpdateTime, + showComponentPoolHelp, manualRefresh, toggleAutoRefresh, changeRefreshInterval, @@ -584,7 +687,8 @@ module.exports = Editor.Panel.define({ getFpsColor, getMemoryColor, getECSTimeColor, - getExecutionTimeColor + getExecutionTimeColor, + openDocumentation }; }, template: readFileSync(join(__dirname, '../../../static/template/debug/index.html'), 'utf-8'), diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/style/debug/index.css b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/style/debug/index.css index 23a3e56f..d46c6743 100644 --- a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/style/debug/index.css +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/style/debug/index.css @@ -10,7 +10,7 @@ background: var(--color-normal-fill); margin: 0; padding: 0; - height: 100vh; + height: 100%; overflow: hidden; } @@ -22,7 +22,7 @@ .debug-container { display: flex; flex-direction: column; - height: 100vh; + height: 100%; background: var(--color-normal-fill); } @@ -660,10 +660,12 @@ ui-button ui-icon { /* ECS调试面板样式 */ .debug-panel { padding: 16px; + padding-bottom: 32px; background: var(--color-normal-fill); color: var(--color-normal-contrast); height: 100%; overflow-y: auto; + overflow-x: hidden; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } @@ -1242,7 +1244,7 @@ ui-button ui-icon { } .debug-panel::-webkit-scrollbar-thumb:hover { - background: var(--color-normal-contrast-weaken); + background-color: var(--color-focus-border-emphasis); } /* 百分比条样式 */ @@ -1261,7 +1263,340 @@ ui-button ui-icon { } .percentage-fill { + background: linear-gradient(90deg, var(--color-primary), var(--color-primary-emphasis)); height: 100%; - background: linear-gradient(90deg, #4CAF50 0%, #FF9800 50%, #F44336 100%); + border-radius: inherit; transition: width 0.3s ease; +} + +/* 调试面板滚动条样式 */ +.debug-panel::-webkit-scrollbar { + width: 8px; +} + +.debug-panel::-webkit-scrollbar-track { + background: var(--color-normal-fill-weaker); + border-radius: 4px; +} + +.debug-panel::-webkit-scrollbar-thumb { + background: var(--color-normal-border); + border-radius: 4px; +} + +.debug-panel::-webkit-scrollbar-thumb:hover { + background: var(--color-focus-border); +} + +/* ============================================ + 帮助面板和文档链接样式 + ============================================ */ + +.section-help { + margin-left: auto; +} + +.help-btn { + display: flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + background: var(--color-normal-fill); + border: 1px solid var(--color-normal-border); + border-radius: 4px; + color: var(--color-default-contrast); + font-size: 11px; + cursor: pointer; + transition: all 0.2s ease; +} + +.help-btn:hover { + background: var(--color-normal-fill-emphasis); + border-color: var(--color-focus-border); + color: var(--color-focus-contrast); +} + +.help-btn ui-icon { + font-size: 12px; +} + +.help-panel { + margin: 16px 0; + padding: 20px; + background: var(--color-normal-fill); + border: 1px solid var(--color-normal-border); + border-radius: 8px; + animation: fadeInDown 0.3s ease; +} + +@keyframes fadeInDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.help-content h4 { + margin: 0 0 12px 0; + color: var(--color-focus-contrast); + font-size: 14px; + font-weight: 600; +} + +.help-content p { + margin: 0 0 16px 0; + color: var(--color-default-contrast); + font-size: 12px; + line-height: 1.5; +} + +.help-steps { + margin: 20px 0; +} + +.help-step { + margin-bottom: 20px; + padding: 16px; + background: var(--color-normal-fill-emphasis); + border-radius: 6px; + border-left: 3px solid var(--color-focus-border); +} + +.help-step:last-child { + margin-bottom: 0; +} + +.help-step h5 { + margin: 0 0 12px 0; + color: var(--color-focus-contrast); + font-size: 12px; + font-weight: 600; +} + +.help-step p { + margin: 0; + color: var(--color-default-contrast); + font-size: 11px; + line-height: 1.4; +} + +.code-example { + background: var(--color-normal-fill); + border: 1px solid var(--color-normal-border); + border-radius: 4px; + padding: 12px; + margin: 8px 0 0 0; + font-family: 'Courier New', monospace; + font-size: 10px; + line-height: 1.4; + color: var(--color-focus-border); + overflow-x: auto; + white-space: pre; +} + +.help-links { + display: flex; + gap: 12px; + margin-top: 16px; + padding-top: 16px; + border-top: 1px solid var(--color-normal-border); +} + +.doc-link { + display: flex; + align-items: center; + gap: 6px; + padding: 8px 12px; + background: var(--color-focus-fill); + border: 1px solid var(--color-focus-border); + border-radius: 4px; + color: var(--color-focus-contrast); + text-decoration: none; + font-size: 11px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; +} + +.doc-link:hover { + background: var(--color-focus-fill-emphasis); + border-color: var(--color-focus-border-emphasis); + transform: translateY(-1px); +} + +.doc-link ui-icon { + font-size: 12px; +} + +.doc-access-note { + display: flex; + align-items: flex-start; + gap: 8px; + margin-top: 12px; + padding: 12px; + background: var(--color-info-fill); + border: 1px solid var(--color-info-border); + border-radius: 4px; + font-size: 10px; + color: var(--color-info-contrast); + line-height: 1.4; +} + +.doc-access-note ui-icon { + font-size: 14px; + color: var(--color-info-border); + margin-top: 1px; + flex-shrink: 0; +} + +/* ============================================ + 组件池相关样式 + ============================================ */ + +.help-tooltip { + display: inline-flex; + align-items: center; + margin-left: 4px; + cursor: help; + color: var(--color-normal-contrast-weaker); +} + +.help-tooltip:hover { + color: var(--color-focus-border); +} + +.help-tooltip ui-icon { + font-size: 10px; +} + +.not-configured { + display: inline-flex; + align-items: center; + margin-left: 4px; + color: var(--color-warn-border); + cursor: help; +} + +.not-configured ui-icon { + font-size: 10px; +} + +.no-pool-hint { + font-size: 10px; + color: var(--color-normal-contrast-weaker); + margin-left: 4px; +} + +.pool-suggestion { + margin-top: 16px; + padding: 16px; + background: linear-gradient(135deg, var(--color-warn-fill) 0%, var(--color-focus-fill) 100%); + border: 1px solid var(--color-warn-border); + border-radius: 8px; + animation: fadeInUp 0.4s ease; +} + +.suggestion-content { + display: flex; + gap: 12px; + align-items: flex-start; +} + +.suggestion-icon { + color: var(--color-warn-border); + font-size: 20px; + margin-top: 2px; +} + +.suggestion-text { + flex: 1; +} + +.suggestion-text h4 { + margin: 0 0 8px 0; + color: var(--color-focus-contrast); + font-size: 13px; + font-weight: 600; +} + +.suggestion-text p { + margin: 0 0 12px 0; + color: var(--color-default-contrast); + font-size: 11px; + line-height: 1.5; +} + +.suggestion-action { + padding: 6px 12px; + background: var(--color-focus-border); + border: none; + border-radius: 4px; + color: white; + font-size: 11px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; +} + +.suggestion-action:hover { + background: var(--color-focus-border-emphasis); + transform: translateY(-1px); +} + +/* ============================================ + 响应式设计增强 + ============================================ */ + +@media (max-width: 768px) { + .help-links { + flex-direction: column; + } + + .doc-link { + justify-content: center; + } + + .suggestion-content { + flex-direction: column; + text-align: center; + } + + .suggestion-icon { + align-self: center; + margin-top: 0; + } +} + +@media (max-width: 480px) { + .help-panel { + padding: 16px; + } + + .help-step { + padding: 12px; + } + + .code-example { + font-size: 9px; + padding: 8px; + } + + .help-btn { + padding: 4px 8px; + font-size: 10px; + } + + .section-header { + flex-direction: column; + align-items: flex-start; + gap: 8px; + } + + .section-help { + margin-left: 0; + } } \ No newline at end of file diff --git a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/debug/index.html b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/debug/index.html index c042de45..39cf312e 100644 --- a/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/debug/index.html +++ b/extensions/cocos/cocos-ecs/extensions/cocos-ecs-extension/static/template/debug/index.html @@ -188,7 +188,68 @@

🧩 组件分析

+
+ +
+ + +
+
+

📖 组件对象池使用指南

+

组件对象池用于复用组件实例,减少频繁创建/销毁组件带来的内存分配开销。当前利用率为0表示还未配置对象池。

+ +
+
+
1. 注册组件对象池
+
import { ComponentPoolManager } from '@esengine/ecs-framework';
+
+// 为Transform组件注册对象池
+ComponentPoolManager.getInstance().registerPool(
+    'Transform',
+    () => new Transform(),
+    (comp) => comp.reset(), // 可选的重置函数
+    100 // 池大小
+);
+
+ +
+
2. 使用对象池获取组件
+
// 从对象池获取组件实例
+const poolManager = ComponentPoolManager.getInstance();
+const transform = poolManager.acquireComponent('Transform');
+
+// 使用完毕后释放回池中
+poolManager.releaseComponent('Transform', transform);
+
+ +
+
3. 查看性能改进
+

正确配置后,利用率栏将显示池的使用情况。利用率越高说明对象池被有效使用,可以减少GC压力。

+
+
+ + + +
+ + 如果无法直接打开文档链接,链接将自动复制到剪贴板,请在浏览器中粘贴访问 +
+
+
+
组件类型: @@ -206,18 +267,45 @@
实例数
内存占用
对象池
-
利用率
+
+ 利用率 + + + +
{{ comp.typeName }}
{{ comp.instanceCount }}
{{ formatMemory(comp.totalMemory) }}
-
{{ comp.poolSize }}
+
+ {{ comp.poolSize || '未配置' }} + + + +
{{ comp.poolUtilization.toFixed(1) }}% + + (无对象池) + +
+
+
+ + +
+
+ +
+

💡 性能优化建议

+

检测到所有组件都未配置对象池。为频繁创建/销毁的组件配置对象池可以显著提升性能,减少垃圾回收压力。

+
diff --git a/src/ECS/Core/ComponentPool.ts b/src/ECS/Core/ComponentPool.ts index 128c8c52..d5533eac 100644 --- a/src/ECS/Core/ComponentPool.ts +++ b/src/ECS/Core/ComponentPool.ts @@ -149,4 +149,38 @@ export class ComponentPoolManager { } return stats; } + + /** + * 获取池利用率信息(用于调试) + */ + getPoolUtilization(): Map { + const utilization = new Map(); + for (const [name, pool] of this.pools) { + const available = pool.getAvailableCount(); + const maxSize = pool.getMaxSize(); + const used = maxSize - available; + const utilRate = maxSize > 0 ? (used / maxSize * 100) : 0; + + utilization.set(name, { + used: used, + total: maxSize, + utilization: utilRate + }); + } + return utilization; + } + + /** + * 获取指定组件的池利用率 + */ + getComponentUtilization(componentName: string): number { + const pool = this.pools.get(componentName); + if (!pool) return 0; + + const available = pool.getAvailableCount(); + const maxSize = pool.getMaxSize(); + const used = maxSize - available; + + return maxSize > 0 ? (used / maxSize * 100) : 0; + } } \ No newline at end of file diff --git a/src/Types/index.ts b/src/Types/index.ts index e4dca197..0d148ab9 100644 --- a/src/Types/index.ts +++ b/src/Types/index.ts @@ -386,6 +386,12 @@ export interface IPerformanceDebugData { samples: number; percentage?: number; // 系统占ECS总时间的百分比 }>; + /** 系统占比分析数据 */ + systemBreakdown?: Array<{ + systemName: string; + executionTime: number; + percentage: number; + }>; /** 内存分配详情 */ memoryDetails?: { entities: number; diff --git a/src/Utils/DebugReporter.ts b/src/Utils/DebugReporter.ts index f279e69f..84fd75d2 100644 --- a/src/Utils/DebugReporter.ts +++ b/src/Utils/DebugReporter.ts @@ -41,6 +41,14 @@ export class DebugReporter { this.config = config; this.sceneStartTime = Date.now(); + // 确保性能监控器在调试模式下被启用 + if (this.config.enabled && this.config.channels.performance) { + if (!this.core._performanceMonitor.isEnabled) { + this.core._performanceMonitor.enable(); + console.log('[ECS Debug] Performance monitor enabled for debugging'); + } + } + if (this.config.enabled) { this.start(); } @@ -80,6 +88,14 @@ export class DebugReporter { this.config = newConfig; + // 根据配置启用或禁用性能监控器 + if (newConfig.enabled && newConfig.channels.performance) { + if (!this.core._performanceMonitor.isEnabled) { + this.core._performanceMonitor.enable(); + console.log('[ECS Debug] Performance monitor enabled for debugging'); + } + } + if (!newConfig.enabled && wasEnabled) { this.stop(); } else if (newConfig.enabled && (!wasEnabled || urlChanged)) { @@ -429,6 +445,7 @@ export class DebugReporter { maxFrameTime: maxECSTime, // ECS最长执行时间 frameTimeHistory: [...this.frameTimeHistory], systemPerformance: this.getSystemPerformance(), + systemBreakdown: ecsPerformanceData.systemBreakdown, memoryDetails: this.getMemoryDetails() }; } @@ -439,6 +456,14 @@ export class DebugReporter { private getECSPerformanceData(): { totalExecutionTime: number; systemBreakdown: Array } { const monitor = this.core._performanceMonitor; if (!monitor) { + console.warn('[ECS Debug] Performance monitor not found'); + return { totalExecutionTime: 0, systemBreakdown: [] }; + } + + if (!monitor.isEnabled) { + console.warn('[ECS Debug] Performance monitor is disabled. Enable it to see ECS performance data.'); + // 尝试启用性能监控器 + monitor.enable(); return { totalExecutionTime: 0, systemBreakdown: [] }; } @@ -448,6 +473,11 @@ export class DebugReporter { const stats = monitor.getAllSystemStats(); + if (stats.size === 0) { + console.log('[ECS Debug] No system performance data available yet. This is normal on first frames.'); + return { totalExecutionTime: 0, systemBreakdown: [] }; + } + // 计算各系统的执行时间 for (const [systemName, stat] of stats.entries()) { const systemTime = stat.averageTime || 0; @@ -468,11 +498,14 @@ export class DebugReporter { // 按执行时间排序 systemBreakdown.sort((a, b) => b.executionTime - a.executionTime); + console.log(`[ECS Debug] Performance data: ${stats.size} systems, total time: ${totalTime.toFixed(2)}ms`); + return { totalExecutionTime: totalTime, systemBreakdown: systemBreakdown }; } catch (error) { + console.error('[ECS Debug] Error getting ECS performance data:', error); return { totalExecutionTime: 0, systemBreakdown: [] }; } } @@ -544,29 +577,56 @@ export class DebugReporter { }); } }); + } else { + // 如果entityManager不存在,尝试从场景直接获取 + const entityList = (scene as any).entities; + if (entityList?.buffer) { + entityList.buffer.forEach((entity: any) => { + entityMemory += this.estimateObjectSize(entity); + + if (entity.components) { + entity.components.forEach((component: any) => { + componentMemory += this.estimateObjectSize(component); + }); + } + }); + } } - // 计算系统内存(估算) + // 计算系统内存 const entitySystems = (scene as any).entitySystems; if (entitySystems?.systems) { entitySystems.systems.forEach((system: any) => { systemMemory += this.estimateObjectSize(system); }); + } else { + // 尝试从entityProcessors获取 + const entityProcessors = (scene as any).entityProcessors; + if (entityProcessors?.processors) { + entityProcessors.processors.forEach((system: any) => { + systemMemory += this.estimateObjectSize(system); + }); + } } - // 计算对象池内存(估算) + // 计算对象池内存 try { - const poolManager = this.core._poolManager; - if (poolManager) { - // 简单估算对象池内存 - pooledMemory = 1024 * 1024; // 1MB估算值 + const { ComponentPoolManager } = require('../ECS/Core/ComponentPool'); + const poolManager = ComponentPoolManager.getInstance(); + const poolStats = poolManager.getPoolStats(); + + for (const [typeName, stats] of poolStats.entries()) { + // 估算每个组件实例的大小 + const estimatedComponentSize = this.calculateComponentMemorySize(typeName); + pooledMemory += stats.available * estimatedComponentSize; } } catch (error) { - // 忽略对象池内存计算错误 + // 如果无法访问ComponentPoolManager,使用估算值 + pooledMemory = 512 * 1024; // 512KB估算值 } // 获取浏览器内存信息 - let totalMemory = 512 * 1024 * 1024; // 默认512MB + let totalMemory = 512 * 1024 * 1024; let usedMemory = entityMemory + componentMemory + systemMemory + pooledMemory; let gcCollections = 0; @@ -637,37 +697,48 @@ export class DebugReporter { } }); + // 获取池利用率信息 + let poolUtilizations = new Map(); + let poolSizes = new Map(); + + try { + const { ComponentPoolManager } = require('../ECS/Core/ComponentPool'); + const poolManager = ComponentPoolManager.getInstance(); + const poolStats = poolManager.getPoolStats(); + const utilizations = poolManager.getPoolUtilization(); + + for (const [typeName, stats] of poolStats.entries()) { + poolSizes.set(typeName, stats.maxSize); + } + + for (const [typeName, util] of utilizations.entries()) { + poolUtilizations.set(typeName, util.utilization); + } + } catch (error) { + // 如果无法获取池信息,使用默认值 + } + return { componentTypes: componentStats.size, componentInstances: totalInstances, componentStats: Array.from(componentStats.entries()).map(([typeName, stats]) => { - const poolSize = this.getComponentPoolSize(typeName); + const poolSize = poolSizes.get(typeName) || 0; + const poolUtilization = poolUtilizations.get(typeName) || 0; const memoryPerInstance = this.calculateComponentMemorySize(typeName); + return { typeName, instanceCount: stats.count, memoryPerInstance: memoryPerInstance, totalMemory: stats.count * memoryPerInstance, poolSize: poolSize, - poolUtilization: poolSize > 0 ? (stats.count / poolSize * 100) : 0, + poolUtilization: poolUtilization, averagePerEntity: stats.count / entityList.buffer.length }; }) }; } - /** - * 获取组件池大小 - */ - private getComponentPoolSize(typeName: string): number { - try { - const poolManager = this.core._poolManager; - return (poolManager as any).getPoolSize?.(typeName) || 0; - } catch (error) { - return 0; - } - } - /** * 计算组件实际内存大小 */