对象池内存管理优化

This commit is contained in:
YHH
2025-10-10 10:16:44 +08:00
parent 7339e7ecec
commit 9445c735c3
3 changed files with 245 additions and 27 deletions

View File

@@ -8,24 +8,41 @@ export class ComponentPool<T extends Component> {
private createFn: () => T; private createFn: () => T;
private resetFn?: (component: T) => void; private resetFn?: (component: T) => void;
private maxSize: number; private maxSize: number;
private minSize: number;
private growthFactor: number;
private stats = {
totalCreated: 0,
totalAcquired: 0,
totalReleased: 0
};
constructor( constructor(
createFn: () => T, createFn: () => T,
resetFn?: (component: T) => void, resetFn?: (component: T) => void,
maxSize: number = 1000 maxSize: number = 1000,
minSize: number = 10,
growthFactor: number = 1.5
) { ) {
this.createFn = createFn; this.createFn = createFn;
this.resetFn = resetFn; this.resetFn = resetFn;
this.maxSize = maxSize; this.maxSize = maxSize;
this.minSize = Math.max(1, minSize);
this.growthFactor = Math.max(1.1, growthFactor);
} }
/** /**
* 获取一个组件实例 * 获取一个组件实例
*/ */
acquire(): T { acquire(): T {
this.stats.totalAcquired++;
if (this.pool.length > 0) { if (this.pool.length > 0) {
return this.pool.pop()!; return this.pool.pop()!;
} }
this.stats.totalCreated++;
return this.createFn(); return this.createFn();
} }
@@ -33,20 +50,41 @@ export class ComponentPool<T extends Component> {
* 释放一个组件实例回池中 * 释放一个组件实例回池中
*/ */
release(component: T): void { release(component: T): void {
if (this.pool.length < this.maxSize) { this.stats.totalReleased++;
if (this.resetFn) {
this.resetFn(component); if (this.pool.length >= this.maxSize) {
} return;
this.pool.push(component);
} }
if (this.resetFn) {
this.resetFn(component);
}
this.pool.push(component);
} }
/** /**
* 预填充对象池 * 预填充对象池
*/ */
prewarm(count: number): void { prewarm(count: number): void {
for (let i = 0; i < count && this.pool.length < this.maxSize; i++) { const targetCount = Math.min(count, this.maxSize);
this.pool.push(this.createFn());
for (let i = this.pool.length; i < targetCount; i++) {
const component = this.createFn();
if (this.resetFn) {
this.resetFn(component);
}
this.pool.push(component);
this.stats.totalCreated++;
}
}
/**
* 自动收缩池大小
*/
shrink(): void {
while (this.pool.length > this.minSize) {
this.pool.pop();
} }
} }
@@ -70,6 +108,35 @@ export class ComponentPool<T extends Component> {
getMaxSize(): number { getMaxSize(): number {
return this.maxSize; return this.maxSize;
} }
/**
* 获取统计信息
*/
getStats() {
const hitRate = this.stats.totalAcquired === 0
? 0
: (this.stats.totalAcquired - this.stats.totalCreated) / this.stats.totalAcquired;
return {
totalCreated: this.stats.totalCreated,
totalAcquired: this.stats.totalAcquired,
totalReleased: this.stats.totalReleased,
hitRate: hitRate,
currentSize: this.pool.length,
maxSize: this.maxSize,
minSize: this.minSize,
utilizationRate: this.pool.length / this.maxSize
};
}
}
/**
* 组件使用追踪
*/
interface ComponentUsageTracker {
createCount: number;
releaseCount: number;
lastAccessTime: number;
} }
/** /**
@@ -78,6 +145,10 @@ export class ComponentPool<T extends Component> {
export class ComponentPoolManager { export class ComponentPoolManager {
private static instance: ComponentPoolManager; private static instance: ComponentPoolManager;
private pools = new Map<string, ComponentPool<any>>(); private pools = new Map<string, ComponentPool<any>>();
private usageTracker = new Map<string, ComponentUsageTracker>();
private autoCleanupInterval = 60000;
private lastCleanupTime = 0;
private constructor() {} private constructor() {}
@@ -95,9 +166,16 @@ export class ComponentPoolManager {
componentName: string, componentName: string,
createFn: () => T, createFn: () => T,
resetFn?: (component: T) => void, resetFn?: (component: T) => void,
maxSize?: number maxSize?: number,
minSize?: number
): void { ): void {
this.pools.set(componentName, new ComponentPool(createFn, resetFn, maxSize)); this.pools.set(componentName, new ComponentPool(createFn, resetFn, maxSize, minSize));
this.usageTracker.set(componentName, {
createCount: 0,
releaseCount: 0,
lastAccessTime: Date.now()
});
} }
/** /**
@@ -105,6 +183,9 @@ export class ComponentPoolManager {
*/ */
acquireComponent<T extends Component>(componentName: string): T | null { acquireComponent<T extends Component>(componentName: string): T | null {
const pool = this.pools.get(componentName); const pool = this.pools.get(componentName);
this.trackUsage(componentName, 'create');
return pool ? pool.acquire() : null; return pool ? pool.acquire() : null;
} }
@@ -113,11 +194,71 @@ export class ComponentPoolManager {
*/ */
releaseComponent<T extends Component>(componentName: string, component: T): void { releaseComponent<T extends Component>(componentName: string, component: T): void {
const pool = this.pools.get(componentName); const pool = this.pools.get(componentName);
this.trackUsage(componentName, 'release');
if (pool) { if (pool) {
pool.release(component); pool.release(component);
} }
} }
/**
* 追踪使用情况
*/
private trackUsage(componentName: string, action: 'create' | 'release'): void {
let tracker = this.usageTracker.get(componentName);
if (!tracker) {
tracker = {
createCount: 0,
releaseCount: 0,
lastAccessTime: Date.now()
};
this.usageTracker.set(componentName, tracker);
}
if (action === 'create') {
tracker.createCount++;
} else {
tracker.releaseCount++;
}
tracker.lastAccessTime = Date.now();
}
/**
* 自动清理(定期调用)
*/
public update(): void {
const now = Date.now();
if (now - this.lastCleanupTime < this.autoCleanupInterval) {
return;
}
for (const [name, tracker] of this.usageTracker.entries()) {
const inactive = now - tracker.lastAccessTime > 120000;
if (inactive) {
const pool = this.pools.get(name);
if (pool) {
pool.shrink();
}
}
}
this.lastCleanupTime = now;
}
/**
* 获取热点组件列表
*/
public getHotComponents(threshold: number = 100): string[] {
return Array.from(this.usageTracker.entries())
.filter(([_, tracker]) => tracker.createCount > threshold)
.map(([name]) => name);
}
/** /**
* 预热所有池 * 预热所有池
*/ */
@@ -137,10 +278,28 @@ export class ComponentPoolManager {
} }
/** /**
* 重置管理器,移除所有注册的池 * 重置管理器
*/ */
reset(): void { reset(): void {
this.pools.clear(); this.pools.clear();
this.usageTracker.clear();
}
/**
* 获取全局统计信息
*/
getGlobalStats() {
const stats: any[] = [];
for (const [name, pool] of this.pools.entries()) {
stats.push({
componentName: name,
poolStats: pool.getStats(),
usage: this.usageTracker.get(name)
});
}
return stats;
} }
/** /**
@@ -158,7 +317,7 @@ export class ComponentPoolManager {
} }
/** /**
* 获取池利用率信息(用于调试) * 获取池利用率信息
*/ */
getPoolUtilization(): Map<string, { used: number; total: number; utilization: number }> { getPoolUtilization(): Map<string, { used: number; total: number; utilization: number }> {
const utilization = new Map(); const utilization = new Map();
@@ -167,7 +326,7 @@ export class ComponentPoolManager {
const maxSize = pool.getMaxSize(); const maxSize = pool.getMaxSize();
const used = maxSize - available; const used = maxSize - available;
const utilRate = maxSize > 0 ? (used / maxSize * 100) : 0; const utilRate = maxSize > 0 ? (used / maxSize * 100) : 0;
utilization.set(name, { utilization.set(name, {
used: used, used: used,
total: maxSize, total: maxSize,
@@ -183,11 +342,11 @@ export class ComponentPoolManager {
getComponentUtilization(componentName: string): number { getComponentUtilization(componentName: string): number {
const pool = this.pools.get(componentName); const pool = this.pools.get(componentName);
if (!pool) return 0; if (!pool) return 0;
const available = pool.getAvailableCount(); const available = pool.getAvailableCount();
const maxSize = pool.getMaxSize(); const maxSize = pool.getMaxSize();
const used = maxSize - available; const used = maxSize - available;
return maxSize > 0 ? (used / maxSize * 100) : 0; return maxSize > 0 ? (used / maxSize * 100) : 0;
} }
} }

View File

@@ -874,8 +874,8 @@ export class Entity {
/** /**
* 销毁实体 * 销毁实体
* *
* 移除所有组件、子实体并标记为已销毁 * 移除所有组件、子实体并标记为已销毁
*/ */
public destroy(): void { public destroy(): void {
if (this._isDestroyed) { if (this._isDestroyed) {
@@ -883,29 +883,66 @@ export class Entity {
} }
this._isDestroyed = true; this._isDestroyed = true;
const childrenToDestroy = [...this._children]; const childrenToDestroy = [...this._children];
for (const child of childrenToDestroy) { for (const child of childrenToDestroy) {
child.destroy(); child.destroy();
} }
if (this._parent) { if (this._parent) {
this._parent.removeChild(this); this._parent.removeChild(this);
} }
this.removeAllComponents(); this.removeAllComponents();
if (this.scene) { if (this.scene) {
if (this.scene.querySystem) { if (this.scene.querySystem) {
this.scene.querySystem.removeEntity(this); this.scene.querySystem.removeEntity(this);
} }
if (this.scene.entities) { if (this.scene.entities) {
this.scene.entities.remove(this); this.scene.entities.remove(this);
} }
} }
} }
/**
* 批量销毁所有子实体
*/
public destroyAllChildren(): void {
if (this._children.length === 0) return;
const scene = this.scene;
const toDestroy: Entity[] = [];
const collectChildren = (entity: Entity) => {
for (const child of entity._children) {
toDestroy.push(child);
collectChildren(child);
}
};
collectChildren(this);
for (const entity of toDestroy) {
entity._isDestroyed = true;
}
for (const entity of toDestroy) {
entity.removeAllComponents();
}
if (scene) {
for (const entity of toDestroy) {
scene.entities.remove(entity);
scene.querySystem.removeEntity(entity);
}
scene.clearSystemEntityCaches();
}
this._children.length = 0;
}
/** /**
* 比较实体 * 比较实体
* *

View File

@@ -12,6 +12,7 @@ import { getComponentInstanceTypeName, getSystemInstanceTypeName } from './Decor
import { TypedQueryBuilder } from './Core/Query/TypedQuery'; import { TypedQueryBuilder } from './Core/Query/TypedQuery';
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer'; import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer'; import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
import { ComponentPoolManager } from './Core/ComponentPool';
/** /**
* 游戏场景默认实现类 * 游戏场景默认实现类
@@ -185,14 +186,13 @@ export class Scene implements IScene {
* 更新场景 * 更新场景
*/ */
public update() { public update() {
// 更新实体列表(处理延迟操作) ComponentPoolManager.getInstance().update();
this.entities.updateLists(); this.entities.updateLists();
// 更新实体处理器
if (this.entityProcessors != null) if (this.entityProcessors != null)
this.entityProcessors.update(); this.entityProcessors.update();
// 更新实体处理器后处理
if (this.entityProcessors != null) if (this.entityProcessors != null)
this.entityProcessors.lateUpdate(); this.entityProcessors.lateUpdate();
} }
@@ -273,13 +273,35 @@ export class Scene implements IScene {
} }
/**
* 批量销毁实体
*/
public destroyEntities(entities: Entity[]): void {
if (entities.length === 0) return;
for (const entity of entities) {
entity._isDestroyed = true;
}
for (const entity of entities) {
entity.removeAllComponents();
}
for (const entity of entities) {
this.entities.remove(entity);
this.querySystem.removeEntity(entity);
}
this.querySystem.clearCache();
this.clearSystemEntityCaches();
}
/** /**
* 从场景中删除所有实体 * 从场景中删除所有实体
*/ */
public destroyAllEntities() { public destroyAllEntities() {
this.entities.removeAllEntities(); this.entities.removeAllEntities();
// 清理查询系统中的实体引用和缓存
this.querySystem.setEntities([]); this.querySystem.setEntities([]);
} }