对象池内存管理优化
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较实体
|
||||
*
|
||||
|
||||
@@ -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([]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user