Files
dns-server/static/js/memory-manager.js
2026-01-29 18:57:20 +08:00

393 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// memory-manager.js - 全局内存管理模块
// 全局内存管理对象
const memoryManager = {
// 缓存管理
caches: {
ipGeolocation: {
data: new Map(),
maxSize: 1000,
order: []
},
domainInfo: {
data: new Map(),
maxSize: 500
},
apiResponses: {
data: new Map(),
maxSize: 100,
ttl: 60000 // 1分钟过期
}
},
// 资源管理
resources: {
timers: [],
eventListeners: [],
webSockets: [],
intervals: []
},
// 内存监控
monitoring: {
enabled: true,
history: [],
maxHistory: 50,
threshold: 80 // 内存使用阈值(%
},
// 初始化
init() {
console.log('内存管理器初始化');
this.startMonitoring();
this.setupGlobalListeners();
},
// 启动内存监控
startMonitoring() {
if (this.monitoring.enabled && performance && performance.memory) {
setInterval(() => {
this.checkMemoryUsage();
}, 30000); // 每30秒检查一次
}
},
// 检查内存使用情况
checkMemoryUsage() {
if (!performance || !performance.memory) return;
const memory = performance.memory;
const usage = {
timestamp: Date.now(),
used: Math.round(memory.usedJSHeapSize / 1024 / 1024 * 100) / 100, // MB
total: Math.round(memory.totalJSHeapSize / 1024 / 1024 * 100) / 100, // MB
limit: Math.round(memory.jsHeapSizeLimit / 1024 / 1024 * 100) / 100, // MB
usagePercent: Math.round((memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100 * 100) / 100 // %
};
this.monitoring.history.push(usage);
// 限制历史记录大小
if (this.monitoring.history.length > this.monitoring.maxHistory) {
this.monitoring.history.shift();
}
// 内存使用过高时的处理
if (usage.usagePercent > this.monitoring.threshold) {
console.warn('内存使用过高:', usage);
this.triggerMemoryCleanup();
}
console.log('内存使用情况:', usage);
},
// 触发内存清理
triggerMemoryCleanup() {
console.log('触发内存清理...');
// 清理缓存
this.cleanupCaches();
// 清理未使用的资源
this.cleanupUnusedResources();
},
// 清理缓存
cleanupCaches() {
// 清理IP地理位置缓存
this.cleanupCache('ipGeolocation');
// 清理域名信息缓存
this.cleanupCache('domainInfo');
// 清理API响应缓存
this.cleanupCache('apiResponses');
},
// 清理特定缓存
cleanupCache(cacheName) {
const cache = this.caches[cacheName];
if (!cache) return;
console.log(`清理${cacheName}缓存 - 当前大小: ${cache.data.size}`);
// 清理超出大小限制的缓存
if (cache.data.size > cache.maxSize) {
if (cache.order && cache.order.length > 0) {
// 使用LRU策略
while (cache.data.size > cache.maxSize && cache.order.length > 0) {
const oldestKey = cache.order.shift();
if (oldestKey) {
cache.data.delete(oldestKey);
}
}
} else {
// 简单清理适用于有TTL的缓存
const now = Date.now();
for (const [key, value] of cache.data.entries()) {
if (cache.data.size <= cache.maxSize) break;
// 检查TTL
if (cache.ttl && value.timestamp && (now - value.timestamp) > cache.ttl) {
cache.data.delete(key);
}
}
// 如果仍然超出大小限制,删除最旧的项
if (cache.data.size > cache.maxSize) {
const keys = Array.from(cache.data.keys());
while (cache.data.size > cache.maxSize && keys.length > 0) {
const oldestKey = keys.shift();
cache.data.delete(oldestKey);
}
}
}
}
console.log(`清理后${cacheName}缓存大小: ${cache.data.size}`);
},
// 清理未使用的资源
cleanupUnusedResources() {
// 清理定时器(这里主要是记录,实际清理需要在具体组件中进行)
console.log(`当前活动定时器数量: ${this.resources.timers.length}`);
console.log(`当前活动事件监听器数量: ${this.resources.eventListeners.length}`);
console.log(`当前活动WebSocket连接数量: ${this.resources.webSockets.length}`);
console.log(`当前活动间隔定时器数量: ${this.resources.intervals.length}`);
},
// 添加缓存项
addCacheItem(cacheName, key, value) {
const cache = this.caches[cacheName];
if (!cache) return;
// 检查缓存大小
if (cache.data.size >= cache.maxSize) {
this.cleanupCache(cacheName);
}
// 添加到缓存
if (cache.ttl) {
cache.data.set(key, {
value,
timestamp: Date.now()
});
} else {
cache.data.set(key, value);
}
// 更新访问顺序用于LRU
if (cache.order) {
// 移除现有的位置
const index = cache.order.indexOf(key);
if (index > -1) {
cache.order.splice(index, 1);
}
// 添加到末尾
cache.order.push(key);
}
},
// 获取缓存项
getCacheItem(cacheName, key) {
const cache = this.caches[cacheName];
if (!cache) return null;
const item = cache.data.get(key);
if (!item) return null;
// 检查TTL
if (cache.ttl && item.timestamp && (Date.now() - item.timestamp) > cache.ttl) {
cache.data.delete(key);
return null;
}
// 更新访问顺序用于LRU
if (cache.order) {
// 移除现有的位置
const index = cache.order.indexOf(key);
if (index > -1) {
cache.order.splice(index, 1);
}
// 添加到末尾
cache.order.push(key);
}
return cache.ttl ? item.value : item;
},
// 注册定时器
registerTimer(timerId) {
if (timerId) {
this.resources.timers.push(timerId);
}
},
// 注销定时器
unregisterTimer(timerId) {
const index = this.resources.timers.indexOf(timerId);
if (index > -1) {
clearTimeout(timerId);
this.resources.timers.splice(index, 1);
}
},
// 注册事件监听器
registerEventListener(element, event, handler) {
if (element && event && handler) {
this.resources.eventListeners.push({ element, event, handler });
}
},
// 注销事件监听器
unregisterEventListener(element, event, handler) {
const index = this.resources.eventListeners.findIndex(item =>
item.element === element && item.event === event && item.handler === handler
);
if (index > -1) {
element.removeEventListener(event, handler);
this.resources.eventListeners.splice(index, 1);
}
},
// 注册WebSocket连接
registerWebSocket(ws) {
if (ws) {
this.resources.webSockets.push(ws);
}
},
// 注销WebSocket连接
unregisterWebSocket(ws) {
const index = this.resources.webSockets.indexOf(ws);
if (index > -1) {
try {
ws.close();
} catch (error) {
console.error('关闭WebSocket连接失败:', error);
}
this.resources.webSockets.splice(index, 1);
}
},
// 注册间隔定时器
registerInterval(intervalId) {
if (intervalId) {
this.resources.intervals.push(intervalId);
}
},
// 注销间隔定时器
unregisterInterval(intervalId) {
const index = this.resources.intervals.indexOf(intervalId);
if (index > -1) {
clearInterval(intervalId);
this.resources.intervals.splice(index, 1);
}
},
// 清理所有资源
cleanupAllResources() {
console.log('清理所有资源...');
// 清理定时器
this.resources.timers.forEach(timerId => {
clearTimeout(timerId);
});
this.resources.timers = [];
// 清理事件监听器
this.resources.eventListeners.forEach(({ element, event, handler }) => {
try {
element.removeEventListener(event, handler);
} catch (error) {
console.error('移除事件监听器失败:', error);
}
});
this.resources.eventListeners = [];
// 清理WebSocket连接
this.resources.webSockets.forEach(ws => {
try {
ws.close();
} catch (error) {
console.error('关闭WebSocket连接失败:', error);
}
});
this.resources.webSockets = [];
// 清理间隔定时器
this.resources.intervals.forEach(intervalId => {
clearInterval(intervalId);
});
this.resources.intervals = [];
// 清理缓存
this.cleanupCaches();
console.log('所有资源已清理');
},
// 设置全局监听器
setupGlobalListeners() {
// 页面卸载时清理所有资源
window.addEventListener('beforeunload', () => {
this.cleanupAllResources();
});
// 页面可见性变化时的处理
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// 页面隐藏时清理一些资源
console.log('页面隐藏,清理资源...');
this.cleanupCaches();
}
});
},
// 获取内存使用统计
getStats() {
if (this.monitoring.history.length === 0) {
return null;
}
const recent = this.monitoring.history[this.monitoring.history.length - 1];
const avg = this.monitoring.history.reduce((sum, item) => sum + item.used, 0) / this.monitoring.history.length;
const max = Math.max(...this.monitoring.history.map(item => item.used));
const min = Math.min(...this.monitoring.history.map(item => item.used));
return {
recent,
avg: Math.round(avg * 100) / 100,
max: Math.round(max * 100) / 100,
min: Math.round(min * 100) / 100,
history: this.monitoring.history,
caches: {
ipGeolocation: this.caches.ipGeolocation.data.size,
domainInfo: this.caches.domainInfo.data.size,
apiResponses: this.caches.apiResponses.data.size
},
resources: {
timers: this.resources.timers.length,
eventListeners: this.resources.eventListeners.length,
webSockets: this.resources.webSockets.length,
intervals: this.resources.intervals.length
}
};
}
};
// 导出内存管理器
if (typeof module !== 'undefined' && module.exports) {
module.exports = memoryManager;
} else {
window.memoryManager = memoryManager;
}
// 自动初始化
if (typeof window !== 'undefined') {
window.addEventListener('DOMContentLoaded', () => {
memoryManager.init();
});
}