大道至简,盘古生其中。计算机的绚丽世界一切都是由0和1组成的
1. 位移运算可以快速的实现乘除运算,那位移时需要注意什么?
①:二进制整数最终都是以补码的形式出现。正数的补码与源码、反码是一样的,而负数的补码是反码加1的结果。位移运算仅作用于整型(32位)和长整型(64位)
②:向右移1位近似表示除以2,十进制的奇数转换为二进制数后,在向右移时,最右边的的1直接被抹除,说明对于奇数并非完全相当于除以2。由于符号位参与移位,正负是移动的后的结果,都有可能是正负数。
注意:(1) 在左移<<
和右移>>
两种运算中,符号位均参与运算,除负数往右移,高位补1之外,其他情况均在空位处补0。(负数的高位是符号位1表示负数,右移补上)
(2) >>>
无符号右移(不存在无符号左移),向右移时,正负数高位都补0,正数不断向右移的最小值是0,负数不断向右移的最小值1(假如在整型上移动位数是32位,无论是否带符号位以及移动方向,均为本身。长整型 mod64,即35<<
1与35<<
65的结果是一样的。负数在无符号位>>>
64 为其原数值本身)
③: &&
和||
都具有短路效果,(短路效果:&&
(逻辑与)前面效果不成立直接退出后面不再执行,||
(逻辑或)前面效果不成立直接退出后面不再执行),按位与&
和按位或|
前后都要执行。
2. 浮点数的存储与计算为什么总产生微小的误差?
- 浮点数表示
单精度(4个字节)32位,1位符号位,8位指数位(阶码位),23位有效数字(尾数为)
①符号位:1负数,0正数
②阶码位:IEEE754标准规定阶码位存储的是指数对应的移码,不是指数的原码或补码。(移码:将一个真值的数轴上正向平移一个偏移量之后得到的值)[X]移 =x+2^(n-1),IEEE754标准规定n=8,指数范围为[-126,127](至于这个结果怎么来的,还有有个过程的)
移码的几何意义是把值映射到一个正数域,特点是可以直观反映两个真值的大小,移码大的真值大,基于这个特点可以高位对齐后直接逐位比较大小,这也是阶码采用移码的原因。
③尾数位:23位存储有效数字
- 加减运算
① 零值检测 两个数都是零直接出结果
② 对阶操作(十进制数中的小数点对齐) 通过比较阶码的大小判断是否对齐,通过移动尾数改变阶码的大小,当相等时表示相等。
尾数向右移动1位,阶码加1,尾数向左移动1位,阶码减1。在移动尾数是,部分二进制位被移除,这也是产生误差的原因,左移高位被移除,造成的误差较大,所以IEEE754标准规定对阶操作时向右移动。
③ 尾数求和 对阶操作完成之后按位相加(如果是负数则需要先转化成补码在进行运算)
④ 结果规范化 若十进制中10.45x10^(38) 右规之后是1.054x10^(39)
⑤ 结果舍入 在对阶或右规时,尾数需要向右移,最右端的呗移除出的位会被丢弃,从而导致结果精度丢失。 为了减少这种精度的丢失,现将移出的这部分数保存起来,并且称为保护位,等到规格化之后再根据保护位进行舍入处理。
- 浮点数的使用
①推荐使用双精度,单精度由于表示区间的限制,计算结果会出现微小误差。
② 禁止通过判断两个浮点数是否相等来控制某些业务流程
③ 数据库保存小数,推荐使用decimal,禁止使用float和double类型
3. 乱码产生的根源是什么?
字符集不兼容造成乱码。编码格式不同,在互相查看源码的时,出现乱码。例如用UTF-8的IDE环境打开GBK源码,中文注释乱码。
4. 代码执行时,CPU是如何与内存配合完成程序使命?
CPU主要有控制器和运算器组成
控制器 (指令控制和时序控制组成)指令编译器在控制单元的协调下完成指令的读取、分析并交给运算器执行,运算完成之后保存回寄存器,甚至内存。
运算器 算术逻辑运算单元,运算器是受控制单元。可以从寄存器提取或存储数据。
平时理解的堆和栈,在CPU眼里都是内存
寄存器 CPU的高速缓存L1、L2 缓存容量是CPU的两个只要想能之一(还有缓存结构)
基于执行指令和热点数据的先后顺序和空间局限性,CPU缓存部分执行和数据,以提升性能,高速缓存远小于内存。
多线程技术和并发更多地依赖操作系统的调配,并行更多依赖于CPU技术
内存和CPU的执行速度从在巨大的鸿沟,若果CPU的性能和容量存在瓶颈,CPU再快也是枉然。
小结: 以C和C++为代表的编程语言。可以直接操作内存地址,进行分配和释放。内存的抽象就是线性空间内的我字节数组,通过下标访问某个特定位置的数据
而已JAVA为代表的编程语言,内存就交给JVM进行自动分配与释放。
5. 网络连接资源耗尽的问题本质是什么?
网络协议
TCP/IP(Transmission Control Protocol/Internet Protocol)传输控制协议/因特网互联协议
应用层 ——> 网络层 ——> 传输层 ——> 网络层 ——> 链路层
| 物理层
应用层 <—— 网络层 <—— 传输层 <—— 网络层 <—— 链路层
总结: 程序在发送消息时,由传输层加上双方端口,在网络层加上双方IP地址,链路层加上双方MAC地址,这样的路径进行数据的封装和发送,解包反过来操作。
TCP建立连接(三次握手)
每个TCP数据包是封装在IP包中的,每一个IP头后紧跟着TCP头。
TCP有6个标记位,重点是SYN:建立连接时的同步信号,ACK:对收到的数据进行确认,所确认的数据由确认序列号决定,FIN:表示后面没有数据需要发送了,连接需要关闭。
三次握手的目的:信息对等和防止超时
三次握手的过程:
① A机器发送一个数据包,并且将SYN置为1,表示希望建立连接。这个包中包括序列号假设为X;
② B机器收到A机器发的包之后,通过SYN知道这个请求是希望建立连接,于是发送一个响应包给并将SYN和ACK设置1,。假设这个包中序列号是Y,而确认序列号是X+1,表示B收到了A的SYN。(在TCP中,SYN被当做数据部分的一个字节)
③A收到B的响应包之后需要确认,确认包中将ACK置为1,并将确认序列号设置为Y+1,表示收到了B的SYN
消息对等:通过三次握手,确认自己的发报和收报能力,确认对方的发报和收报能力
防止超时: 防止出现请求超时导致脏链接:报文的生存时间(TTL)一般超过TCP请求超时时间
TCP断开链接
TCP建立链接要三次,而挥手断开需要四次。
① A机器想关闭链接,则等自己发送数据完毕后,传递FIN消息给B
② B机器确认收到数据确认ACK,告诉A机器可以断开,但是需要等待B机器处理完数据,再主动发动FIN消息给A机器。这是A机器处于半关闭状态(FIN_WAIT_2
),不能在发送数据
③ B机器处理完数据了,发动FIN消息给A机器,此时B机器处于半关闭状态(CLOSE_WAIT
)
④ A机器收到B机器发送的FIN消息之后,发送针对B机器FIN的ACK,之后进入TIME-WAIT
状态,经过2MSL(报文在网络上生存的最长时间),没有收到B机器发送的报文,则确定B机器收到A机器最后发送的ACK指令,此时TCP连接正式释放。
总结:TIME_WAIT
和CLOSE_WAIT
分别表示主动关闭和被动关闭产生的阶段性状态,若果在服务器大量出现这两种状态,会加重机器负载,也会影响有效连接的创建。
因为TIME_WAIT
状态无法真正的释放句柄资源,在此期间,Socket的使用的本地端口默认情况下不能再被使用,这也是网络连接资源耗尽的本质。该限制对于客户端机器来说无所谓,但对于并发服务器来说,极大地限制有效连接创建数量。
6. 黑客攻击的通常套路是什么?如何有效地防止?
XSS(Cross-Site Scripting) 跨站脚本攻击与CSRF(Cross-Site Request Forgery 跨站请求伪造)
XSS:向正常用户请求的HTML页面中插入恶意脚本,从而可以执行任意脚本。(用户数据没有过滤)
防范:通过对用户输入数据做过滤或转义
CSRF:在用户不知情的情况下,冒充用户发起请求,在当前登录的web应用中执行恶意操作,如改密码、发邮件等。是黑客直接盗用用户浏览器中的登录信息,冒充用户操作。(HTTP接口没有防范不受信任的调用)
防范:①在HTTP接口执行前验证页面或Cookie中的Token ②人机交互(短信验证码)
2019/1/18 0:13:02