JavaScript系列(53)--内存管理与垃圾回收机制详解

JavaScript内存管理与垃圾回收机制详解 🧹

今天,让我们深入探讨JavaScript的内存管理与垃圾回收机制。理解这些机制对于编写高性能、无内存泄漏的JavaScript应用至关重要。

内存管理基础概念 🌟

💡 小知识:JavaScript的内存管理是自动的,使用垃圾回收器(Garbage Collector,GC)来自动释放不再使用的内存。主要有两种回收算法:标记-清除(Mark-Sweep)和引用计数(Reference Counting)。

垃圾回收算法实现 📊

// 1. 引用计数垃圾回收
class ReferenceCounter {
    constructor() {
        this.references = new WeakMap();
    }
    
    addReference(object) {
        const count = this.references.get(object) || 0;
        this.references.set(object, count + 1);
    }
    
    removeReference(object) {
        const count = this.references.get(object);
        if (count > 1) {
            this.references.set(object, count - 1);
        } else {
            this.references.delete(object);
        }
    }
    
    isGarbage(object) {
        return !this.references.has(object);
    }
}

// 2. 标记-清除垃圾回收
class MarkAndSweep {
    constructor() {
        this.objects = new Set();
        this.marks = new WeakSet();
    }
    
    addObject(object) {
        this.objects.add(object);
    }
    
    mark(root) {
        // 如果对象已经被标记,直接返回
        if (this.marks.has(root)) return;
        
        // 标记当前对象
        this.marks.add(root);
        
        // 递归标记所有引用
        for (const reference of this.getReferences(root)) {
            this.mark(reference);
        }
    }
    
    sweep() {
        const garbage = [];
        
        for (const object of this.objects) {
            if (!this.marks.has(object)) {
                garbage.push(object);
                this.objects.delete(object);
            }
        }
        
        // 清除标记
        this.marks = new WeakSet();
        
        return garbage;
    }
    
    getReferences(object) {
        const references = [];
        
        // 获取对象的所有属性引用
        for (const key in object) {
            if (typeof object[key] === 'object' && object[key] !== null) {
                references.push(object[key]);
            }
        }
        
        return references;
    }
}

// 3. 分代垃圾回收
class GenerationalGC {
    constructor() {
        this.youngGeneration = new Set();
        this.oldGeneration = new Set();
        this.survivorSpace = new Set();
        this.maxYoungSize = 1000000; // 1MB
        this.promotionThreshold = 3;
    }
    
    allocate(object) {
        if (this.youngGeneration.size >= this.maxYoungSize) {
            this.minorGC();
        }
        
        this.youngGeneration.add({
            object,
            age: 0
        });
    }
    
    minorGC() {
        // 标记-复制算法
        for (const item of this.youngGeneration) {
            if (this.isReachable(item.object)) {
                item.age++;
                if (item.age >= this.promotionThreshold) {
                    // 晋升到老年代
                    this.oldGeneration.add(item.object);
                } else {
                    // 移动到幸存区
                    this.survivorSpace.add(item);
                }
            }
        }
        
        // 清空年轻代
        this.youngGeneration = this.survivorSpace;
        this.survivorSpace = new Set();
    }
    
    majorGC() {
        // 对老年代进行完整的标记-清除
        const markAndSweep = new MarkAndSweep();
        
        for (const object of this.oldGeneration) {
            markAndSweep.addObject(object);
        }
        
        // 从根对象开始标记
        const roots = this.getRoots();
        for (const root of roots) {
            markAndSweep.mark(root);
        }
        
        // 清除未标记对象
        const garbage = markAndSweep.sweep();
        for (const object of garbage) {
            this.oldGeneration.delete(object);
        }
    }
    
    isReachable(object) {
        // 实现可达性分析
        const visited = new Set();
        const stack = [object];
        
        while (stack.length > 0) {
            const current = stack.pop();
            if (!visited.has(current)) {
                visited.add(current);
                
                // 检查是否有根引用
                if (this.isRoot(current)) {
                    return true;
                }
                
                // 添加所有引用到栈中
                for (const reference of this.getReferences(current)) {
                    stack.push(reference);
                }
            }
        }
        
        return false;
    }
}

内存泄漏检测 🔍

// 1. 内存泄漏检测器
class MemoryLeakDetector {
    constructor() {
        this.snapshots = [];
        this.leakThreshold = 1000000; // 1MB
    }
    
    takeSnapshot() {
        const snapshot = {
            timestamp: Date.now(),
            memory: performance.memory.usedJSHeapSize,
            objects: this.getObjectCounts()
        };
        
        this.snapshots.push(snapshot);
        return snapshot;
    }
    
    getObjectCounts() {
        const counts = new Map();
        
        // 遍历全局对象
        for (const key in window) {
            const value = window[key];
            if (typeof value === 'object' && value !== null) {
                const type = value.constructor.name;
                counts.set(type, (counts.get(type) || 0) + 1);
            }
        }
        
        return counts;
    }
    
    detectLeaks() {
        if (this.snapshots.length < 2) {
            return null;
        }
        
        const latest = this.snapshots[this.snapshots.length - 1];
        const previous = this.snapshots[this.snapshots.length - 2];
        
        const memoryDiff = latest.memory - previous.memory;
        const leaks = new Map();
        
        // 检查对象数量变化
        for (const [type, count] of latest.objects) {
            const prevCount = previous.objects.get(type) || 0;
            const diff = count - prevCount;
            
            if (diff > 0) {
                leaks.set(type, diff);
            }
        }
        
        return {
            memoryDiff,
            leaks,
            isSignificant: memoryDiff > this.leakThreshold
        };
    }
}

// 2. 循环引用检测
class CircularReferenceDetector {
    detect(object, path = new Set()) {
        // 如果对象已经在路径中,发现循环引用
        if (path.has(object)) {
            return true;
        }
        
        // 只检查对象类型
        if (typeof object !== 'object' || object === null) {
            return false;
        }
        
        // 将当前对象添加到路径
        path.add(object);
        
        // 递归检查所有属性
        for (const key in object) {
            if (this.detect(object[key], path)) {
                return true;
            }
        }
        
        // 从路径中移除当前对象
        path.delete(object);
        return false;
    }
    
    findCircularPaths(object, path = [], seen = new Set()) {
        const paths = [];
        
        if (typeof object !== 'object' || object === null) {
            return paths;
        }
        
        if (seen.has(object)) {
            paths.push([...path]);
            return paths;
        }
        
        seen.add(object);
        
        for (const key in object) {
            path.push(key);
            paths.push(...this.findCircularPaths(object[key], path, seen));
            path.pop();
        }
        
        seen.delete(object);
        return paths;
    }
}

// 3. 内存使用分析器
class MemoryAnalyzer {
    constructor() {
        this.samples = [];
        this.interval = null;
    }
    
    startSampling(interval = 1000) {
        this.interval = setInterval(() => {
            this.takeSample();
        }, interval);
    }
    
    stopSampling() {
        if (this.interval) {
            clearInterval(this.interval);
            this.interval = null;
        }
    }
    
    takeSample() {
        const sample = {
            timestamp: Date.now(),
            memory: performance.memory.usedJSHeapSize,
            heapLimit: performance.memory.jsHeapSizeLimit,
            allocation: this.getRecentAllocations()
        };
        
        this.samples.push(sample);
        
        // 保持最近100个样本
        if (this.samples.length > 100) {
            this.samples.shift();
        }
        
        return sample;
    }
    
    getRecentAllocations() {
        // 获取最近的内存分配情况
        if (this.samples.length < 2) {
            return 0;
        }
        
        const latest = this.samples[this.samples.length - 1];
        const previous = this.samples[this.samples.length - 2];
        
        return latest.memory - previous.memory;
    }
    
    getAnalysis() {
        if (this.samples.length < 2) {
            return null;
        }
        
        const memoryGrowth = this.samples.reduce((acc, sample, index) => {
            if (index === 0) return acc;
            const growth = sample.memory - this.samples[index - 1].memory;
            return acc + growth;
        }, 0);
        
        const averageGrowth = memoryGrowth / (this.samples.length - 1);
        const maxMemory = Math.max(...this.samples.map(s => s.memory));
        const minMemory = Math.min(...this.samples.map(s => s.memory));
        
        return {
            averageGrowth,
            maxMemory,
            minMemory,
            memoryUtilization: maxMemory / this.samples[0].heapLimit,
            trend: averageGrowth > 1000 ? 'increasing' : 'stable'
        };
    }
}

性能优化策略 ⚡

// 1. 对象池实现
class ObjectPool {
    constructor(factory, initialSize = 10) {
        this.factory = factory;
        this.pool = [];
        this.activeObjects = new WeakSet();
        
        // 初始化对象池
        for (let i = 0; i < initialSize; i++) {
            this.pool.push(this.factory());
        }
    }
    
    acquire() {
        let object = this.pool.pop();
        
        if (!object) {
            object = this.factory();
        }
        
        this.activeObjects.add(object);
        return object;
    }
    
    release(object) {
        if (this.activeObjects.has(object)) {
            this.activeObjects.delete(object);
            
            // 重置对象状态
            if (object.reset) {
                object.reset();
            }
            
            this.pool.push(object);
        }
    }
    
    get size() {
        return this.pool.length;
    }
}

// 2. 内存限制器
class MemoryLimiter {
    constructor(maxMemory = 100 * 1024 * 1024) { // 100MB
        this.maxMemory = maxMemory;
        this.currentMemory = 0;
        this.allocations = new WeakMap();
    }
    
    allocate(size) {
        if (this.currentMemory + size > this.maxMemory) {
            throw new Error('Memory limit exceeded');
        }
        
        const object = new ArrayBuffer(size);
        this.allocations.set(object, size);
        this.currentMemory += size;
        
        return object;
    }
    
    free(object) {
        const size = this.allocations.get(object);
        if (size) {
            this.currentMemory -= size;
            this.allocations.delete(object);
        }
    }
    
    get availableMemory() {
        return this.maxMemory - this.currentMemory;
    }
}

// 3. 缓存管理器
class CacheManager {
    constructor(maxSize = 1000) {
        this.maxSize = maxSize;
        this.cache = new Map();
        this.accessCount = new Map();
    }
    
    set(key, value, ttl = 3600000) { // 默认1小时
        if (this.cache.size >= this.maxSize) {
            this.evictLeastUsed();
        }
        
        this.cache.set(key, {
            value,
            expires: Date.now() + ttl
        });
        this.accessCount.set(key, 0);
    }
    
    get(key) {
        const entry = this.cache.get(key);
        
        if (!entry) {
            return null;
        }
        
        if (entry.expires < Date.now()) {
            this.cache.delete(key);
            this.accessCount.delete(key);
            return null;
        }
        
        this.accessCount.set(key, this.accessCount.get(key) + 1);
        return entry.value;
    }
    
    evictLeastUsed() {
        let leastUsedKey = null;
        let leastUsedCount = Infinity;
        
        for (const [key, count] of this.accessCount) {
            if (count < leastUsedCount) {
                leastUsedKey = key;
                leastUsedCount = count;
            }
        }
        
        if (leastUsedKey) {
            this.cache.delete(leastUsedKey);
            this.accessCount.delete(leastUsedKey);
        }
    }
    
    cleanup() {
        const now = Date.now();
        for (const [key, entry] of this.cache) {
            if (entry.expires < now) {
                this.cache.delete(key);
                this.accessCount.delete(key);
            }
        }
    }
}

最佳实践建议 💡

  1. 内存优化模式
// 1. 弱引用处理
class WeakRefHandler {
    constructor() {
        this.refs = new WeakMap();
        this.registry = new FinalizationRegistry(key => {
            console.log(`Object with key ${key} has been garbage collected`);
        });
    }
    
    addRef(key, object) {
        const ref = new WeakRef(object);
        this.refs.set(key, ref);
        this.registry.register(object, key);
    }
    
    getRef(key) {
        const ref = this.refs.get(key);
        return ref ? ref.deref() : null;
    }
}

// 2. 大数据处理
class LargeDataHandler {
    constructor() {
        this.chunkSize = 1000;
    }
    
    *processInChunks(data) {
        for (let i = 0; i < data.length; i += this.chunkSize) {
            const chunk = data.slice(i, i + this.chunkSize);
            yield this.processChunk(chunk);
        }
    }
    
    processChunk(chunk) {
        // 处理数据块的逻辑
        return chunk.map(item => item * 2);
    }
}

// 3. 资源释放管理
class ResourceManager {
    constructor() {
        this.resources = new Set();
    }
    
    acquire(resource) {
        this.resources.add(resource);
        return resource;
    }
    
    release(resource) {
        if (this.resources.has(resource)) {
            if (resource.dispose) {
                resource.dispose();
            }
            this.resources.delete(resource);
        }
    }
    
    releaseAll() {
        for (const resource of this.resources) {
            this.release(resource);
        }
    }
}

结语 📝

JavaScript的内存管理和垃圾回收机制是确保应用性能和稳定性的关键。通过本文,我们学习了:

  1. 内存管理的基本原理
  2. 垃圾回收算法的实现
  3. 内存泄漏的检测和防范
  4. 性能优化策略
  5. 最佳实践和设计模式

💡 学习建议:在开发中要时刻注意内存使用情况,特别是在处理大量数据或长期运行的应用时。合理使用内存优化工具和模式,可以显著提升应用的性能和稳定性。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/963433.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ResNet--深度学习中的革命性网络架构

一、引言 在深度学习的研究和应用中&#xff0c;网络架构的设计始终是一个关键话题。随着计算能力和大数据的不断提升&#xff0c;深度神经网络逐渐成为解决复杂任务的主流方法。然而&#xff0c;随着网络层数的增加&#xff0c;训练深度神经网络往往面临梯度消失或梯度爆炸的…

HTML特殊符号的使用示例

目录 一、基本特殊符号的使用 1、空格符号&#xff1a; 2、小于号 和 大于号&#xff1a; 3、引号&#xff1a; 二、版权、注册商标符号的使用 1、版权符号&#xff1a;© 2、注册商标符号&#xff1a; 三、数学符号的使用 四、箭头符号的使用 五、货币符号的使用…

C++11—右值引用

目录 简介 左值和右值 左值 右值 右值引用 生命周期 引用折叠 实际应用 移动语义 移动构造函数 移动赋值运算符 完美转发 简介 之前我们曾学习过引用叫左值引用&#xff0c;但那是C98的&#xff0c;在C11中新增了一种引用叫右值引用。右值引用主要用于支持移动语…

Ubuntu下的Doxygen+VScode实现C/C++接口文档自动生成

Ubuntu下的DoxygenVScode实现C/C接口文档自动生成 Chapter1 Ubuntu下的DoxygenVScode实现C/C接口文档自动生成1、 Doxygen简介1. 安装Doxygen1&#xff09;方法一&#xff1a;2&#xff09;方法二&#xff1a;2. doxygen注释自动生成插件3. doxygen注释基本语法4. doxygen的生成…

函数与递归

函数与递归 声明或者定义应该在使用之前&#xff08;不单单针对于函数&#xff09; 函数对全局变量做出的改变还是不会随着函数结束而消失的 函数声明在main函数里面也是可以的 引用变量和引用实体的变化是一样的 传址调用比传值调用效率高 重载函数->编译器会根据传递…

网络编程套接字(中)

文章目录 &#x1f34f;简单的TCP网络程序服务端创建套接字服务端绑定服务端监听服务端获取连接服务端处理请求客户端创建套接字客户端连接服务器客户端发起请求服务器测试单执行流服务器的弊端 &#x1f350;多进程版的TCP网络程序捕捉SIGCHLD信号让孙子进程提供服务 &#x1…

96,【4】 buuctf web [BJDCTF2020]EzPHP

进入靶场 查看源代码 GFXEIM3YFZYGQ4A 一看就是编码后的 1nD3x.php 访问 得到源代码 <?php // 高亮显示当前 PHP 文件的源代码&#xff0c;用于调试或展示代码结构 highlight_file(__FILE__); // 关闭所有 PHP 错误报告&#xff0c;防止错误信息泄露可能的安全漏洞 erro…

C++模板编程——可变参函数模板之折叠表达式

目录 1. 什么是折叠表达式 2. 一元左折 3. 一元右折 4. 二元左折 5. 二元右折 6. 后记 上一节主要讲解了可变参函数模板和参数包展开&#xff0c;这一节主要讲一下折叠表达式。 1. 什么是折叠表达式 折叠表达式是C17中引入的概念&#xff0c;引入折叠表达式的目的是为了…

如何用微信小程序写春联

​ 生活没有模板,只需心灯一盏。 如果笑能让你释然,那就开怀一笑;如果哭能让你减压,那就让泪水流下来。如果沉默是金,那就不用解释;如果放下能更好地前行,就别再扛着。 一、引入 Vant UI 1、通过 npm 安装 npm i @vant/weapp -S --production​​ 2、修改 app.json …

openRv1126 AI算法部署实战之——TensorFlow TFLite Pytorch ONNX等模型转换实战

Conda简介 查看当前系统的环境列表 conda env list base为基础环境 py3.6-rknn-1.7.3为模型转换环境&#xff0c;rknn-toolkit版本V1.7.3&#xff0c;python版本3.6 py3.6-tensorflow-2.5.0为tensorflow模型训练环境&#xff0c;tensorflow版本2.5.0&#xff0c;python版本…

电介质超表面中指定涡旋的非线性生成

涡旋光束在众多领域具有重要应用&#xff0c;但传统光学器件产生涡旋光束的方式限制了其在集成系统中的应用。超表面的出现为涡旋光束的产生带来了新的可能性&#xff0c;尤其是在非线性领域&#xff0c;尽管近些年来已经有一些研究&#xff0c;但仍存在诸多问题&#xff0c;如…

Python3 OS模块中的文件/目录方法说明十七

一. 简介 前面文章简单学习了 Python3 中 OS模块中的文件/目录的部分函数。 本文继续来学习 OS 模块中文件、目录的操作方法&#xff1a;os.walk() 方法、os.write()方法 二. Python3 OS模块中的文件/目录方法 1. os.walk() 方法 os.walk() 方法用于生成目录树中的文件名&a…

2025年2月2日(网络编程 tcp)

tcp 循环服务 import socketdef main():# 创建 socket# 绑定tcp_server socket.socket(socket.AF_INET, socket.SOCK_STREAM)tcp_server.bind(("", 8080))# socket 转变为被动tcp_server.listen(128)while True:# 产生专门为链接进来的客户端服务的 socketprint(&qu…

Rust 中的注释使用指南

Rust 中的注释使用指南 注释是代码中不可或缺的一部分&#xff0c;它帮助开发者理解代码的逻辑和意图。Rust 提供了多种注释方式&#xff0c;包括行注释、块注释和文档注释。本文将详细介绍这些注释的使用方法&#xff0c;并通过一个示例展示如何在实际代码中应用注释。 1. 行…

使用Pygame制作“青蛙过河”游戏

本篇博客将演示如何使用 Python Pygame 从零开始编写一款 Frogger 风格的小游戏。Frogger 是一款早期街机经典&#xff0c;玩家需要帮助青蛙穿越车水马龙的马路到达对岸。本示例提供了一个精简原型&#xff0c;包含角色移动、汽车生成与移动、碰撞检测、胜利条件等关键点。希望…

渗透测试过程中碰到的Symfony框架

0x01 不是很顺利的Nday利用 在一次渗透测试过程中发现了目标使用了Symfony框架&#xff0c;然后扫了下目录&#xff0c;发现存在app_dev.php 文件&#xff0c;尝试访问 发现开启了debug模式&#xff0c;Symfony 版本号为2.8.34 php版本5.6.40 也能查看phpinfo页面 然后在网上搜…

Games104——网络游戏的进阶架构

这里写目录标题 前言位移移动插值内插&#xff08;Interpolation&#xff09;外插&#xff08;Extrapolation&#xff09; 命中判定Hit Registration在客户端去判定 在服务器端去判定延迟补偿掩体问题躲进掩体走出掩体 技能前摇本地暴击效果 基础MMO框架分布式架构一致性哈希服…

2025年01月27日Github流行趋势

项目名称&#xff1a;onlook项目地址url&#xff1a;https://github.com/onlook-dev/onlook项目语言&#xff1a;TypeScript历史star数&#xff1a;5340今日star数&#xff1a;211项目维护者&#xff1a;Kitenite, drfarrell, iNerdStack, abhiroopc84, apps/dependabot项目简介…

【Redis】set 和 zset 类型的介绍和常用命令

1. set 1.1 介绍 set 类型和 list 不同的是&#xff0c;存储的元素是无序的&#xff0c;并且元素不允许重复&#xff0c;Redis 除了支持集合内的增删查改操作&#xff0c;还支持多个集合取交集&#xff0c;并集&#xff0c;差集 1.2 常用命令 命令 介绍 时间复杂度 sadd …

[SAP ABAP] 静态断点的使用

在 ABAP 编程环境中&#xff0c;静态断点通过关键字BREAK-POINT实现&#xff0c;当程序执行到这一语句时&#xff0c;会触发调试器中断程序的运行&#xff0c;允许开发人员检查当前状态并逐步跟踪后续代码逻辑 通常情况下&#xff0c;在代码的关键位置插入静态断点可以帮助开发…