对象池内存管理优化

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 resetFn?: (component: T) => void;
private maxSize: number;
private minSize: number;
private growthFactor: number;
private stats = {
totalCreated: 0,
totalAcquired: 0,
totalReleased: 0
};
constructor(
createFn: () => T,
resetFn?: (component: T) => void,
maxSize: number = 1000
maxSize: number = 1000,
minSize: number = 10,
growthFactor: number = 1.5
) {
this.createFn = createFn;
this.resetFn = resetFn;
this.maxSize = maxSize;
this.minSize = Math.max(1, minSize);
this.growthFactor = Math.max(1.1, growthFactor);
}
/**
* 获取一个组件实例
*/
acquire(): T {
this.stats.totalAcquired++;
if (this.pool.length > 0) {
return this.pool.pop()!;
}
this.stats.totalCreated++;
return this.createFn();
}
@@ -33,20 +50,41 @@ export class ComponentPool<T extends Component> {
* 释放一个组件实例回池中
*/
release(component: T): void {
if (this.pool.length < this.maxSize) {
if (this.resetFn) {
this.resetFn(component);
}
this.pool.push(component);
this.stats.totalReleased++;
if (this.pool.length >= this.maxSize) {
return;
}
if (this.resetFn) {
this.resetFn(component);
}
this.pool.push(component);
}
/**
* 预填充对象池
*/
prewarm(count: number): void {
for (let i = 0; i < count && this.pool.length < this.maxSize; i++) {
this.pool.push(this.createFn());
const targetCount = Math.min(count, this.maxSize);
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 {
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 {
private static instance: ComponentPoolManager;
private pools = new Map<string, ComponentPool<any>>();
private usageTracker = new Map<string, ComponentUsageTracker>();
private autoCleanupInterval = 60000;
private lastCleanupTime = 0;
private constructor() {}
@@ -95,9 +166,16 @@ export class ComponentPoolManager {
componentName: string,
createFn: () => T,
resetFn?: (component: T) => void,
maxSize?: number
maxSize?: number,
minSize?: number
): 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 {
const pool = this.pools.get(componentName);
this.trackUsage(componentName, 'create');
return pool ? pool.acquire() : null;
}
@@ -113,11 +194,71 @@ export class ComponentPoolManager {
*/
releaseComponent<T extends Component>(componentName: string, component: T): void {
const pool = this.pools.get(componentName);
this.trackUsage(componentName, 'release');
if (pool) {
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 {
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 }> {
const utilization = new Map();

View File

@@ -875,7 +875,7 @@ export class Entity {
/**
* 销毁实体
*
* 移除所有组件、子实体并标记为已销毁
* 移除所有组件、子实体并标记为已销毁
*/
public destroy(): void {
if (this._isDestroyed) {
@@ -906,6 +906,43 @@ export class Entity {
}
}
/**
* 批量销毁所有子实体
*/
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 { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
import { ComponentPoolManager } from './Core/ComponentPool';
/**
* 游戏场景默认实现类
@@ -185,14 +186,13 @@ export class Scene implements IScene {
* 更新场景
*/
public update() {
// 更新实体列表(处理延迟操作)
ComponentPoolManager.getInstance().update();
this.entities.updateLists();
// 更新实体处理器
if (this.entityProcessors != null)
this.entityProcessors.update();
// 更新实体处理器后处理
if (this.entityProcessors != null)
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() {
this.entities.removeAllEntities();
// 清理查询系统中的实体引用和缓存
this.querySystem.setEntities([]);
}