首页 > 其他分享 >记录--千万别让 console.log 上生产!用 Performance 和 Memory 告诉你为什么

记录--千万别让 console.log 上生产!用 Performance 和 Memory 告诉你为什么

时间:2023-02-10 17:13:24浏览次数:77  
标签:泄漏 console log -- GC 内存 代码执行

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

很多前端都喜欢用 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 会导致内存泄漏呢?

因为控制台打印的对象,你是不是有可能展开看?那如果这个对象在内存中没有了,是不是就看不到了?

所以有这个引用在,浏览器不会把你打印的对象的内存释放掉。

有的同学说,那我不打开控制台,是不是就没有这个引用了?

答案是否定的:

2023-01-05 18.34.31.gif

我点击了几次之后,再打开控制台,依然是可以看到这个对象的,说明没有被 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,--,GC,内存,代码执行
From: https://www.cnblogs.com/smileZAZ/p/17109664.html

相关文章

  • Jedis快速入门和操作string
    Jedis快速入门Jedis:一款java操作redis数据库的工具使用步骤:1.下载jedis的jar包2.导入依赖  使用:packagecom.example.test;importorg.junit.Test;......
  • windows安全加固
    背景等保要求,做windows安全加固,为方便快捷,bat脚本安排。适用适用于windowsserver2008和windowsserver2012,其他版本还没试过,有待调试。脚本win_security_hardenin......
  • 控制bin文件夹里面的dll不复制到临时目录中
    web.config中<!--shadowCopyBinAssemblies可选的Boolean特性。设置一个布尔值,该值指示Bin目录中的应用程序的程序集是否影像复制到该应用程序的ASP.NET临......
  • springboot开发日记(10)——web开发
    通过SpringInitializer进行项目创建文件->新建项目->选中SpringInitializer->勾选所需的插件和项目类型(本次勾选插件为:lombok、dev-tools、SpringConfigurationProcessor,......
  • Docker Compose容器编排
    一、Docker-Compose1.1、什么是DockerComposeCompose项目是Docker官方的开源项目,负责实现Docker容器集群的快速编排,开源代码在https://github.com/docker/compo......
  • qt 卡拉OK 歌词效果
    //思路:一、先绘制全部歌词二、设置裁剪区域三、绘制已经唱的歌词voidWidget::paintEvent(QPaintEvent*event){QLineFline(10.0,80.0,90.0,20.0);QPainter......
  • SpringMVC数据绑定
    SpringMVC数据绑定使用JavaBean绑定参数SpringMVC会根据请求参数名和JavaBean属性名进行自动匹配,自动为对象填充属性值,同时支持级联属性packagecom.soutwind.entity......
  • JvirsualVM
    一眼就能看出某人是社会上最可怜的的那类人,他们的可怜之处不仅仅在于物质,更多是精神上的卑微。就像果戈里笔下的那些小职员,虽然社会地位已经很低下,却仍然为保住这种地位而......
  • PHP redis 分布式锁 实现
    <?php/***redis分布式锁*/classRedisLock{private$config;private$redis;publicfunction__construct($config=[]){$this->config=$confi......
  • EasyCVR视频云存储的架构解析与Sharelist云存挂载方法介绍
    一、什么是视频云存储?视频云存储主要用于为上层应用提供视频文件、结构化信息、事件信息的相关服务。云存储节点分为数据文件存储节点和结构化数据存储节点。数据文件存储......