记录--千万别让 console.log 上生产!用 Performance 和 Memory 告诉你为什么
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
很多前端都喜欢用 console.log 调试,先不谈调试效率怎么样,首先 console.log 有个致命的问题:会导致内存泄漏。
为什么这么说呢?
用 Performance 和 Memory 工具分析下就知道了。
我们准备这样一段代码:
一个按钮,点击之后创建一个数组,执行一些计算。
很常见的逻辑。
我们最后加了一个 console.log 打印了下这个数组。
起个静态服务:
浏览器访问:
点击 performance 下的垃圾回收按钮,手动触发一次 GC:
勾选 Memory,然后开始录制,点击 3 次按钮,再执行一次 GC:
你会发现内存是这样的:
内存占用有三次增长,因为我们点击三次按钮的时候会创建 3 次大数组。
但是最后我们手动 GC 之后并没有回落下去,也就是这个大数组没有被回收。
按理来说,代码执行完,那用的内存就要被释放,然后再执行别的代码,结果这段代码执行完之后大数组依然占据着内存,这样别的代码再执行的时候可用内存就少了。
这就是发生了内存泄漏,也就是代码执行完了不释放内存的流氓行为。
有同学说,只是这么一点内存问题不大呀,反正可用内存还很多。
但如果你的代码要跑很长时间,这段代码要执行很多次呢?
每次执行都会占据一部分内存不释放,慢慢的内存就不够用了,甚至会导致程序崩溃。
比如当这段代码执行个 9 次,内存占用就增长了 9 个大数组的内存:
再多执行几次呢?
是不是就有崩溃的隐患了。
那为啥说是 console.log 导致的呢?
我们来看看不用 console.log 是什么样的:
注释掉 console.log,重新跑。
你会发现现在的内存分配情况是这样的:
分配了三次内存,但是 GC 后又会落下去了。
这才是没有内存泄漏的好代码。
那为啥 console.log 会导致内存泄漏呢?
因为控制台打印的对象,你是不是有可能展开看?那如果这个对象在内存中没有了,是不是就看不到了?
所以有这个引用在,浏览器不会把你打印的对象的内存释放掉。
有的同学说,那我不打开控制台,是不是就没有这个引用了?
答案是否定的:
我点击了几次之后,再打开控制台,依然是可以看到这个对象的,说明没有被 GC。
也就是说用 console.log 打印对象的代码一定是有内存泄漏的。
当然,也不只是 console.log 会导致内存泄漏,还有别的 4 种情况:
- 定时器用完了没有清除,那每次执行都会多一个定时器的内存占用,这就是内存泄漏
- 元素从 dom 移除了,但是还有一个变量引用着他,这样的游离的 dom 元素也不会被回收。每执行一次代码,就会多出游离的 dom 元素的内存,这也是内存泄漏
- 闭包引用了某个变量,这个变量不会被回收,如果这样的闭包比较多,那每次执行都会多出这些被引用变量的内存占用。这样引用大对象的闭包多了之后,也会导致内存问题
- 全局变量,这个本来就不会被 GC,要注意全局变量的使用
总之,全局变量、闭包引用的变量、被移除的 dom 依然被引用、定时器用完了没清除、console.log 都会发生代码执行完了,但是还占用着一部分内存的流氓行为,也就是内存泄漏。
注意,这里指的是使用完毕后没有回收,在使用期间的内存增长是正常的。
那怎么排查呢?
performance 工具就可以:
点击内存分配情况的某个点,就会定位到 performance 中的某个任务的代码,点击可以在下面看到详情:
这样就定位到了分配内存的代码,分析一下哪里会有问题即可。
当然,前提还是要执行先 GC,再做一些操作,再 GC 的这个流程。
这是从代码角度来分析内存泄漏,其实还可以从内存中对象的角度,这个是通过 Memory 工具:
先 GC,录制一次内存快照,再点击几次按钮,然后 GC,再录制一次内存快照。
流程和用 performance 分析的时候一样。
拿到两次内存快照也是可以分析出有内存泄漏的:
可以看到 GC 后内存占用依然增长了。
快照记录着这个时刻内存中所有对象的状态:
对比两次快照,就可以找到变化的部分:
比如这时候可以看到最大的内存增长是 array 对象:
然后就可以从 array 的角度去思考是什么导致的内存泄漏了。
此外,memory 还有实时分析的工具:
选择第二个,然后点几次按钮:
其实不用手动 GC,JS 引擎会做 GC。
去掉 console.log 再录制是这样的:
除了最开始全局变量会分配一些内存以外,点击按钮之后的内存变蓝后又变灰了,也就是被 GC 了。
这样你点多少次按钮,内存占用都没有增长。
这就是代码执行完,会回收所有用到的内存的好代码。
而前面的那个是每次代码执行,都会占用一部分内存不释放的内存泄漏代码。
你还可以看到每一次内存分配的对象是啥:
不管是用 Performance 工具还是 Memory 工具,都可以发现 console.log 有内存泄漏的问题。所以还是尽量不要用这个来调试了。
那应该用什么呢?
用 debugger 呀,不管是 vscode debugger 还是 chrome devtools 的都可以:
你可以添加一个 logpoint 来代替 console.log 打印:
代码执行到这里就会打印:
而你的代码里不需要写 console.log。
此外,很多地方可以用断点代替打印:
可以看到代码执行路线和作用域,岂不是更高效?
总结
console.log 会导致内存泄漏,也就是代码执行完了,但还占据着一部分内存的流氓行为。
除了 console.log,游离的 dom 被变量引用、全局变量、变量被闭包引用、定时器没清除也会导致内存泄漏。
我们可以用 Performance 工具和 Memory 工具分析内存泄漏。
先手动 GC,然后执行一些操作,再 GC,如果内存没有回到执行前,就说明这段代码有内存泄漏,可以再用 Performance 定位到代码位置分析代码。
Memory 工具是从内存对象的角度分析,可以对两次快照做 diff,看下是啥对象泄漏了。
也可以实时检测内存占用情况,看看是否存在内存泄漏,对象是啥。
console.log 调试效率也不高,可以换成 logpoint,或者打断点。
千万不要把 console.log 上生产!不然这样有内存泄漏的代码,一旦执行时间长了就会有问题。
其实普通项目也还好,不会长期跑,但是类似大屏项目这种长期跑的,一旦有内存泄漏,一定会崩溃,只有时间长短的区别。
本文转载于:
https://juejin.cn/post/7185128318235541563
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
记录--千万别让 console.log 上生产!用 Performance 和 Memory 告诉你为什么的更多相关文章
- vue生产环境清除console.log
npm run build 后的生产环境的代码,会有很多开发时留下的console.log(),不可能每个页面不停地删除 在build/webpack.prod.conf.js文件里加上这样一段代码即 ...
- vue在生产环境清除console.log
在开发环境中我们喜欢用console.log测试代码,但是部署到生产环境我们不可能一个一个把console.log给手动删除了. 在build/webpack.prod.conf.js文件里加上这样一 ...
- vue-cli2.0和vue-cli3.0中当发布到生产环境时禁用console.log
vue-cli2.0中的方法 1.安装插件 npm install uglifyjs-webpack-plugin --save-dev 2.修改webpack.prod.conf.js配置文件 co ...
- Javascript的console.log()用法
Firebug & Chrome Console 控制台的一些其他功能console.log(object[, object, ...])使用频率最高的一条语句:向控制台输出一条消息.支持 C ...
- 前端不为人知的一面--前端冷知识集锦 前端已经被玩儿坏了!像console.log()可以向控制台输出图片
前端已经被玩儿坏了!像console.log()可以向控制台输出图片等炫酷的玩意已经不是什么新闻了,像用||操作符给变量赋默认值也是人尽皆知的旧闻了,今天看到Quora上一个帖子,瞬间又GET了好多前 ...
- 小谈chrome调试命令:console.log的使用
相信从事前端开发的您,一定不会陌生Mozilla五星级推荐的一款插件:firebug,它是如此强大,乃至于我们可以很方便地调试DHTML的近乎所有元素.而在它深邃的机体里,还存有一个命令:consol ...
- console.log 用法
转自http://www.cnblogs.com/ctriphire/p/4116207.html 大家都有用过各种类型的浏览器,每种浏览器都有自己的特色,本人拙见,在我用过的浏览器当中,我是最喜欢C ...
- 推荐前端开发手机调试打印神器console.log()
下面说的这个插件很牛,相信很多人都不知道,但找问题的时候很需要,直接上干货如下: vConsole:一个轻量.可拓展.针对手机网页的前端开发者调试面板. 下载 vConsole 的最新版本.(不要直接 ...
- 【转】console.log 用法
标签: 转自http://www.cnblogs.com/ctriphire/p/4116207.html 大家都有用过各种类型的浏览器,每种浏览器都有自己的特色,本人拙见,在我用过的浏览器当中,我是 ...
- js调试console.log使用总结图解
一 实例 打印字符串和对象: 可展开对象查看内部情况: 看一下console对象本身的定义情况: 输出对象情况: utag对象所在文件: 输出对象: 二 Console.log 总结 1 如果你j ...
随机推荐
- C++ 单例模式以及内存管理
引用: https://zhuanlan.zhihu.com/p/37469260 https://www.cnblogs.com/xiaolincoding/p/11437231.html http ...
- NC23048 月月给华华出题
题目链接 题目 题目描述 因为月月是个信息学高手,所以她也给华华出了一题,让他求: \(\sum_{i=1}^N\frac{i}{\gcd(i,N)}\) 但是因为这个式子实在太简单了,所以月月希望华 ...
- java 从零开始手写 RPC (02)-netty4 实现客户端和服务端
说明 上一篇代码基于 socket 的实现非常简单,但是对于实际生产,一般使用 netty. 至于 netty 的优点可以参考: 为什么选择 netty? http://houbb.github.io ...
- 【Unity3D】GUI控件
1 前言 Unity 3D 提供了 GUI.NGUI.UGUI 等图形系统,以增强玩家与游戏的交互性.GUI 在编译时不能可视化,在运行时才能可视化.GUI 代码需要在 OnGUI 函数中调用才能 ...
- 公司服务器建站笔记(三):腾讯云服务器CentOS8.2安装界面环境,使用vnc远程登陆并搭建轻量级Qt服务器
前言 有些小项目可能只有几个点,几十个点,几百个点,这个时候使用qt的tcp服务器或者mqtt或者websocket等相关服务就可以满足,腾讯云CentOs8.2服务器安装的是没有界面的版本,本篇 ...
- 项目实战:Qt编译Qt库以及使用C#调用Qt库,并实现C#集成Qt的tcp客户端
需求 1.Qt已经开发了应用,封装成Qt库,以供C#调用. 2.Qt的tcp客户端封装,以供C#调用,双向传递数据. 原理 1.使用QtCreator编译msvc版本的Qt库: 2.使 ...
- 【LeetCode哈希表#1】有效的字母异位词+赎金信(数组)
有效的字母异位词 力扣题目链接(opens new window) 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词. 示例 1: 输入: s = "anagr ...
- pip相关知识
正常安装语法 # 安装单个 pip install some-package # 安装指定版本 pip install some-package==版本号 # 查看当前模块版本号 pip instal ...
- mongo重启、远程连接
1.查看当前mongo启动进程 ps -ef | grep mongo 2.修改mongo启动远程连接配制文件 vi /etc/mongod.conf 将 bind_ip=127.0.0.1 这一行注 ...
- CentOS系统下,配制nginx代理
1.安装: yum install nginx 2.证书文件位置: a. 创建https证书文件夹:/etc/nginx/ssl b. 上传两个证书文件到/etc/nginx/ssl 3.在/etc/ ...