技术标签: js 参数解构
起源是在写webscoket服务的时候,发现开发工具偶尔报Maximum call stack size exceeded的问题。由于当时没时间,就草草把BUG修复了,并未深究原因。现在复盘工作的时候,又想起这个问题,于是再把这个问题拿出来研究。
出错代码大概是如下:
new Array().push(...Buffer.allocUnsafe(2**17))
一开始看到超出调用栈以为是Buffer的迭代器递归出现了问题,但事实并不是这样。
排查出错原因
由于出错代码是这样的:
/*
* 而且存在临界点,不同机器略有差异
* 本人的机器大于2**17就必报
*/
new Array().push(...Buffer.allocUnsafe(2**17))
当时认为是Buffer的迭代器问题,所以就尝试使用普通数组
/*
* 这段代码在浏览器也报错
* 所以排除nodejs原因,应该是V8造成的
*/
new Array().push(...new Array(2**17).fill(0xff))
发现普通数组也存在类似问题,接下来就是排除迭代器
[...new Array(2**17).fill(0xff)]
发现迭代居然没有异常,难道是push方法?那就换个方法试试
console.log(...new Array(2**17).fill(0xff))
居然log也报错,那真相只有一个,那就是参数超载了
那为什么会报超过最大调用堆栈大小,而不是其它错误?
大家都知道,函数再调用函数的时候,是通过存储在调用栈中来保持执行顺序的,而栈是有一定大小,比如递归上数百万次后也会出现爆栈。
那么是否真的是因为栈不够用了?还是说参数对调用栈也存在一些影响?接下来我们就来逐一排查。首先确定是否是真的因为栈不够用了
# 通过调整栈大小,来判断是否是栈耗尽了,stack-size的单位是KB,默认是984
node --stack-size=2048 -e "new Array().push(...Buffer.allocUnsafe(2**17))"
发现果然运行正常,所以可以确定是栈耗尽了排查参数的数量对栈的影响
function recursionDepth(paramLen) {
let deepth = 0;
function f(...paramList) {
deepth++;
Math.random() + f(...paramList); // 防止尾递归优化
}
try{
f(...Buffer.allocUnsafe(paramLen))
} catch (err) {
console.log(`当参数长度为${paramLen},最大深度则为:${deepth}`)
}
}
recursionDepth(2**4)
recursionDepth(2**8)
recursionDepth(2**12)
recursionDepth(2**16)
recursionDepth(2**20)
输出结果:
当参数长度为16,最大深度则为:3489
当参数长度为256,最大深度则为:455
当参数长度为4096,最大深度则为:30
当参数长度为65536,最大深度则为:1
当参数长度为1048576,最大深度则为:0
所以由此确定参数的数量也是需要暂用调用栈的空间,而当参数长度达到足够长,即使1帧也可以压垮整个调用栈,超出调用栈空间。
在不同的数据库中关键字的定义是不一样的,有些在DB2中不是关键字,但在ORACLE确是关键字,这就麻烦了,我们系统本来是在基于DB2的 ,迁移到oacle之后发现出现了很多sql语句错误,幸亏我们basis同事的提醒,原来是sql语句中出现了很多关键字,但是改起来又很麻烦,还有解决方案,可以在sql语句中对关键字加双引号,而且还必须大写,所以以后数据库字段命名必须小心...
当启动Fiddler,进入到百度页面或者其它的HTTPS页面,提示:NET::ERR_CERT_AUTHORITY_INVALID,如下图所示:解决方法:进入到Tools–> Fiddler Options–>HTTPS 页面; 点击Actions–>Trust Root Certificate,添加Fiddler证书到列表中; 一直点击【Yes】按钮,直至提示成功即可。...
NAME fmemopen, open_memstream, open_wmemstream - open memory as streamSYNOPSIS #include <stdio.h> FILE *fmemopen(void *buf, size_t size, const char *mode); F...
正常我们所指兼容性测试,兼容性测试包括哪些方面?首次,app兼容性测试在海量机型上通过自动化的方式,针对安装、启动、运行、功能、性能、UI等多维度,定位APP兼容性问题,并提供详细测试报告。帮助企业解决由于兼容性问题而引起的客户投诉、客户流失等问题,提升产品的竞争力。其次,pc端兼容性测试通过搭配不同操作系统、分辨率与浏览器的组合,针对Web网站和PC端软件在多场景、多系统、多维度下,深度发现软件在不同载体上的兼容性问题,帮助企业解决应用软件兼容适配、Web网站兼容浏览器等问题,为企业软件质量保驾护
【题目描述】输入三个整数,整数之间由一个空格分隔,整数是32位有符号整数。把第二个输入的整数输出。【输入】只有一行,共三个整数,整数之间由一个空格分隔。整数是32位有符号整数。【输出】只有一行,一个整数,即输入的第二个整数。【输入样例】123 456 789【输出样例】456【源代码】#include<iostream>usi...
前提条件:先使用工具连上服务器地址。我使用的是Xshell,传文件到服务器的工具是Xftp1.mysql 下载地址:http://mirrors.sohu.com/mysql/MySQL-5.5/选择下载下面这3个文件即可:1. 先使用yum命令高速安装依赖包libaio,输入:yum install libaio 2.安装mysql_server,如果文件没有执行
什么是数据持久化数据持久化是把程序中的数据以某种形式保存到某种存储介质中,达到程序重启时不丢失的作用。Java持久化技术序列化(Serialization)序列化(Serialization)也叫串行化,是Java内置的持久化Java对象机制。只要某个类实现了java.io.Serializable接口,就能够使用java.io.ObjectOutputStream将该类对象以
SECOND: Sparsely Embedded Convolutional Detection重庆大学,输变电设备与系统安全国家重点实验室,2018,KITTI总结基于体素划分的3D卷积网络可以较好的处理lidar信息,但是有推理速度慢和朝向估计的性能差的不足。本文贡献:提出了一种改进的稀疏卷积网络,应用于基于LiDAR的目标检测任务中,显著提高了训练和推理的速度引入新的朝...
导读:最近在做项目的过程中,发现一个问题,就是我们最开始的时候,传递参数包括返回类型,都有map类型。但是由于map每次都要匹配key值,很麻烦。所以在之后就将参数传递和返回类型全都改成了实体bean,并且让每个bean都...
基本的数位DP,注意记录那些状态可以用最小的空间判断出整除性。#include <cstdio>#include <cstring>using namespace std;#define D(x) const int MAX_DIGIT_NUM = 20;int f[MAX_DIGIT_NUM];long long memoi...
基于vue框架在mounted()函数中,初始化某一个元素的css样式,发现无法成功。解决办法:使用nextTickthis.$nextTick()函数作用是等页面的数据更新完成以后,它再执行内部回调函数中的逻辑参考如下:<div> <span ref="red">我需要初始化颜色</span></div>new Vue({ ...