[面试题]字节后台端开发工程师-业务研发岗位

面经

业务背景题

问:业务背景:某浪微博平台有很多用户时常的会发布微博,当某个用户发布一条微博的时候,TA的所有关注着都可以接收到这条信息。那么怎么样设计一个合理的解决方案来让用户快速将他所发布的微博信息推送给所有的关注者呢?

答:
第一种方案,每个用户所发送的微博都存储起来(时间上有序)。当用户要刷新微博的时候就可以直接拉取TA所关注的人在这个时间内的微博,然后按照时间排序之后再推送过来。(当然,这里的什么延迟拉取之类的细节优化就不做详述了。)

机智的小伙伴可能也发现了这种方案的问题,对于某浪微博这种级别的平台,他所支撑的用户都是数以亿计的,这样的方案对于读的压力将会是巨大的

那么怎么办呢?当我们试图开始要优化一个系统的时候,有个相对无脑而又实用的方案就是——上缓存

方案二具体操作说起来也比较简单,对每个用户都维护一块缓存。当用户发布微博的时候,相应的后台程序可以先查询一下他的关注者,然后将这条微博插入到所有关注着的缓存中。(当然这个缓存会按时间线排序,也会有一定的容量大小限制等,这些细节也不多做赘述。)这样当用户上线逛微博的时候,那么TA就可以直接从缓存中读取,读取的性能有了质的飞升。

如此就OK了吗?显然不是,这种方案的问题在于么有考虑到大V的存在,大V具有很庞大的流量扇出。比如微博女王谢娜的粉丝将近1.25亿,那么她发一条微博(假设为1KB)所要占用的缓存大小为1KB * 1.25 * 10^8 = 125GB。对于这个量我们思考一下几个点:

  1. 对于1.25亿人中有多少人会在这个合适的时间在线,有多少人会刷到这条微博,很多像皮皮这种的半僵尸用户也不会太少,这块里面的很多容量都是浪费。
  2. 1.25亿次的缓存写入,虽然不需要瞬时写入,但好歹也要在几秒内完成的吧。这个流量的剧增带来的影响也不容忽视。
  3. 微博上虽然上亿粉丝的大V不多,但是上千万、上百万的大V也是一个不小的群体。某个大V发1条微博就占用了这么大的缓存,这个机器成本也太庞大了,得不偿失。
    【注】这种案例比较典型,比如某直播平台,当PDD上线直播时(直播热度一般在几百万甚至上千万级别)所用的后台支撑策略与某些小主播(直播热度几千之内的)的后台支撑的策略肯定是不一样的。

从微观角度而言,计算机应用是0和1的世界,而从宏观角度来看,计算机应用的艺术确是在0-1之间。通用型业务设计的难点在于要考虑很多种方面的因数,然后权衡利弊,再对症下药。业务架构本没有什么银弹,有的是对系统的不断认知和优化改进。

对于本文这个问题的解决方法是将方案一和二合并,以粉丝数来做区分。也就是说,对于大V发布的微博我们用方案一处理,而对于普通用户而言我们就用方案二来处理。当某个用户逛微博的时候,后台程序可以拉取部分缓存中的信息,与此同时可以如方案一中的方式读取大V的微博信息,最后将此二者做一个时间排序合并后再推送给用户。

———————————————— 版权声明:本文为CSDN博主「朱小厮」的原创文章,遵循 CC 4.0 BY-SA
版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013256816/article/details/100570732

计算机网网络

一、交换机和路由器有什么区别?

答:
1、路由器可以给你的局域网自动分配IP,虚拟拨号,就像一个交通警察,指挥着你的电脑该往哪走,你自己不用操心那么多了。交换机只是用来分配网络数据的。
2、路由器在网络层,路由器根据IP地址寻址,路由器可以处理TCP/IP协议,交换机不可以。交换机在中继层,交换机根据MAC地址寻址。
3、路由器可以把一个IP分配给很多个主机使用,这些主机对外只表现出一个IP。交换机可以把很多主机连起来,这些主机对外各有各的IP。
4、路由器可以提供防火墙,交换机不能提供该功能。集线器、交换机都是做端口扩展的,就是扩大局域网(通常都是以太网)的接入点,也就是能让局域网可以连进来更多的电脑。路由器是用来做网间连接,也就是用来连接不同的网络。

二、OSI七层参考模型

OSI(Open System Interconnect),即开放式系统互联。
ISO为了更好的使网络应用更为普及,推出了OSI参考模型。其含义就是推荐所有公司使用这个规范来控制网络。这样所有公司都有相同的规范,就能互联了。

OSI七层模型的划分
在这里插入图片描述
(1)应用层
OSI参考模型中最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各种网络服务。我们常见应用层的网络服务协议有:HTTP,HTTPS,FTP,POP3、SMTP等。
(2)表示层
表示层提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。如果必要,该层可提供一种标准表示形式,用于将计算机内部的多种数据格式转换成通信中采用的标准表示形式。数据压缩和加密也是表示层可提供的转换功能之一。
(3)会话层
会话层就是负责建立、管理和终止表示层实体之间的通信会话。该层的通信由不同设备中的应用程序之间的服务请求和响应组成。
(4)传输层
传输层建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。我们通常说的,TCP 、UDP就是在这一层。端口号既是这里的“端”。
(5)网络层
本层通过IP寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。就是通常说的IP层。这一层就是我们经常说的IP协议层。IP协议是Internet的基础。
(6)数据链路层
将比特组合成字节,再将字节组合成帧,使用链路层地址 (以太网使用MAC地址)来访问介质,并进行差错检测
数据链路层又分为2个子层:逻辑链路控制子层(LLC)媒体访问控制子层(MAC)
MAC子层处理CSMA/CD算法、数据出错校验、成帧等;LLC子层定义了一些字段使上次协议能共享数据链路层。 在实际使用中,LLC子层并非必需的。
(7)物理层
实际最终信号的传输是通过物理层实现的。通过物理介质传输比特流。规定了电平、速度和电缆针脚。常用设备有(各种物理设备)集线器、中继器、调制解调器、网线、双绞线、同轴电缆。这些都是物理层的传输介质

通信特点:对等通信,在每一层通信过程中,使用本层自己协议进行通信。源端OSI模型的每一层都必须与目的端的对等层进行通信,这种通信方式称为对等层通信。

三、TCP/IP五层模型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、tcp和udp的区别

答:tcp和udp他们都是传输层的协议;然后tcp是可靠传输,udp是尽最大努力交付,不可靠;tcp主要应用于端到端的比如电话这种服务,udp应用于广播,收音机等服务;tcp头部含有更多的如目标地址等信息,比udp头部开销更大。

五、TCP握手过程 为什么是4次

三次握手(Three-way Handshake),一个虚拟连接的建立是通过三次握手来实现的。
四次握手(Four-way Handshake) , 四次握手用来关闭已建立的TCP连接

问:为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
答:这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

详细分析:
(1)三次握手建立连接,客户端发送syn包到服务器,服务器收到syn包,确认客户的syn包并且自己也发送一个syn包和ACK确认包,客户端收到后确认服务器的syn包,连接建立。
详细过程如下:

1、 (B) --> [SYN] --> (A)
假如服务器A和客户机B通讯. 当A要和B通信时,B首先向A发一个SYN (Synchronize)
标记的包,告诉A请求建立连接.
注意: 一个 SYN包就是仅SYN标记设为1的TCP包(参见TCP包头Resources). 认识
到这点很重要,只有当A受到B发来的SYN包,才可建立连接,除此之外别无他法。因此,
如果你的防火墙丢弃所有的发往外网接口的SYN包,那么你将不能让外部任何主机主动建立连接。
2.、(B) <-- [SYN/ACK] <–(A) 接着,A收到后会发一个对SYN包的确认包(SYN/ACK)回去,表示对第一个SYN包的确认,并继续握手操作.
注意: SYN/ACK包是仅SYN 和 ACK 标记为1的包.
3、 (B) --> [ACK] --> (A)
B收到SYN/ACK 包,B发一个确认包(ACK),通知A连接已建立。至此,三次握手完成,一个TCP连接完成
Note: ACK包就是仅ACK 标记设为1的TCP包. 需要注意的是当三此握手完成、连接建立以后,TCP连接的每个包都会设置ACK位

这就是为何连接跟踪很重要的原因了. 没有连接跟踪,防火墙将无法判断收到的ACK包是否属于一个已经建立的连接.一般的包过滤(Ipchains)收到ACK包时,会让它通过(这绝对不是个好主意). 而当状态型防火墙收到此种包时,它会先在连接表中查找是否属于哪个已建连接,否则丢弃该包

(2)四次握手 Four-way Handshake
四次握手用来关闭已建立的TCP连接

  1. (B) --> ACK/FIN --> (A)
  2. (B) <-- ACK <-- (A)
  3. (B) <-- ACK/FIN <-- (A)
  4. (B) --> ACK --> (A)

注意: 由于TCP连接是双向连接, 因此关闭连接需要在两个方向上做。ACK/FIN 包(ACK 和FIN 标记设为1)通常被认为是FIN(终结)包.然而, 由于连接还没有关闭, FIN包总是打上ACK标记. 没有ACK标记而仅有FIN标记的包不是合法的包,并且通常被认为是恶意的

连接复位Resetting a connection
四次握手不是关闭TCP连接的唯一方法. 有时,如果主机需要尽快关闭连接(或连接超时,端口或主机不可达),RST (Reset)包将被发送. 注意在,由于RST包不是TCP连接中的必须部分, 可以只发送RST包(即不带ACK标记). 但在正常的TCP连接中RST包可以带ACK确认标记 .

请注意RST包是可以不要收到方确认的

无效的TCP标记Invalid TCP Flags
到目前为止,你已经看到了 SYN, ACK, FIN, 和RST 标记. 另外,还有PSH (Push) 和URG (Urgent)标记.

最常见的非法组合是SYN/FIN 包. 注意:由于 SYN包是用来初始化连接的, 它不可能和 FIN和RST标记一起出现. 这也是一个恶意攻击.

由于现在大多数防火墙已知 SYN/FIN 包, 别的一些组合,例如SYN/FIN/PSH,
SYN/FIN/RST, SYN/FIN/RST/PSH。很明显,当网络中出现这种包时,很你的网络肯定受到攻击了。
别的已知的非法包有FIN (无ACK标记)和"NULL"包。如同早先讨论的,由于ACK/FIN包的出现是为了关闭一个TCP连接,那么正常的FIN包总是带有 ACK 标记。"NULL"包就是没有任何TCP标记的包(URG,ACK,PSH,RST,SYN,FIN都为0)。

到目前为止,正常的网络活动下,TCP协议栈不可能产生带有上面提到的任何一种标记组合的TCP包。当你发现这些不正常的包时,肯定有人对你的网络不怀好意。

补问:

问:为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
答:这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文。

超时重传:超时重传机制用来保证TCP传输的可靠性。每次发送数据包时,发送的数据报都有seq号(seq的话就是一个临时交互号,是自身的一个标识),接收端收到数据后,会回复ack进行确认,表示某一seq 号数据已经收到。发送方在发送了某个seq包后,等待一段时间,如果没有收到对应的ack回复,就会认为报文丢失,会重传这个数据包。

快速重传:接受数据一方发现有数据包丢掉了。就会发送ack报文告诉发送端重传丢失的报文。如果发送端连续收到标号相同的ack包,则会触发客户端的快速重 传。比较超时重传和快速重传,可以发现超时重传是发送端在傻等超时,然后触发重传;而快速重传则是接收端主动告诉发送端数据没收到,然后触发发送端重传

流量控制:接收端告诉发送端自己还有多少缓冲区可以接受数据(只考虑接收端和发送端)

拥塞控制:慢启动、拥塞避免、拥塞发生、快速恢复(考虑整个网络的状况)

四次握手断开连接

第一次:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当 然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,主动关闭方依然会重发这些数据),但此时主动关闭方还可以接受数据。
第二次:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。
第三次:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。
第四次:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

SYN标志建立一个新连接,FIN标志释一个连接,RST重置连接

三次握手用于防止“已失效的连接请求报文段”,报文段没有丢失,而是在某个节点长时间滞留。
四次挥手:由于TCP连接是全双工的。所以每个方向都必须单独进行关闭

六、https 了解吗

https=http+ssl
https 的 SSL 加密是在传输层实现的。

http: 超文本传输协议

https: 是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版,即 HTTP 下加入
SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。

https 协议的主要作用是:建立一个信息安全通道,来确保数组的传输,确保网
站的真实性。

七、HTTP 与 HTTPS 的区别


1、HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
2、使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
3、HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
4、http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
5、HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。

HTTP超文本传输协议(HyperText Transfer Protocol)是一种用于分布式、协作式和超媒体信息系统的应用层协议。 简单来说就是一种发布和接收 HTML 页面的方法,被用于在 Web 浏览器和网站服务器之间传递信息。

HTTP 默认工作在 TCP 协议 80 端口,用户访问网站 http:// 打头的都是标准 HTTP 服务。
HTTP 协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。

HTTPS超文本传输安全协议(Hypertext Transfer Protocol Secure:)是一种透过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。HTTPS 默认工作在 TCP 协议443端口。
工作流程一般如以下方式:

1、TCP 三次同步握手
2、客户端验证服务器数字证书
3、DH 算法协商对称加密算法的密钥、hash 算法的密钥
4、SSL安全加密隧道协商完成
5、网页以加密的方式传输,用协商的对称加密算法和密钥加密,保证数据机密性;用协商的hash算法进行数据完整性保护,保证数据不被篡改。

八、HTTPs的加密算法是什么

参考链接:https://blog.csdn.net/qq_32998153/article/details/80022489

在交换密钥阶段使用公开密钥加密方式,之后建立通信交换报文阶段则使用共享密钥加密方式。

共享密钥加密(对称密钥加密):加密和解密同用一个密钥。加密时就必须将密钥传送给对方,那么如何安全的传输呢?

公开密钥加密(非对称密钥加密):公开密钥加密使用一对非对称的密钥。一把叫做私有密钥,一把叫做公开密钥。私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。使用此加密方式,发送密文的一方使用公开密钥进行加密处理,对方收到被加密的信息后,再使用自己的私有密钥进行解密。利用这种方式,不需要发送用来解密的私有密钥,也不必担心密钥被攻击者窃听盗走。
但由于公开密钥比共享密钥要慢,所以我们就需要综合一下他们两者的优缺点,使他们共同使用,而这也是HTTPS采用的加密方式。在交换密钥阶段使用公开密钥加密方式,之后建立通信交换报文阶段则使用共享密钥加密方式。

这里就有一个问题,如何证明公开密钥本省是货真价实的公开密钥。如,正准备和某台服务器建立公开密钥加密方式下的通信时,如何证明收到的公开密钥就是原本预想的那台服务器发行的公开密钥。或许在公开密钥传输过程中,真正的公开密钥已经被攻击者替换掉了。为了解决这个问题,可以使用由数字证书认证机构(CA,Certificate Authority) 和其他相关机关颁发的 公开密钥证书

接收到证书的客户端可以使用数字证书认证机构的公开密钥,对那张证书上的数字签名进行验证,一旦验证通过,客户端便可以明确两件事:
(1)认证服务器的公开密钥的是真实有效的数字证书认证机构。
(2)服务器的公开密钥是值得信赖的。

九、TCP相比于UDP为什么可靠

(1)确认和重传机制

建立连接时三次握手同步双方的“序列号 + 确认号 + 窗口大小信息”,是确认重传、流量控制的基础
传输过程中,如果Checksum校验失败、丢包或延时,发送端重传

(2)数据排序

TCP有专门的序列号SN字段,可提供数据re-order

(3)流量控制

窗口和计时器的使用。TCP窗口中会指明双方能够发送接收的最大数据量

(4)拥塞控制

TCP的拥塞控制由4个核心算法组成。
“慢启动”(Slow Start)
“拥塞避免”(Congestion avoidance)
“快速重传 ”(Fast Retransmit)
“快速恢复”(Fast Recovery)

十、为什么发送 http 请求,却建立的是 TCP 连接?

几乎所有的 HTTP 通信都是由 TCP/IP 承载的
HTTP 协议是在 TCP/IP 传输层上的应用层协议,TCP 为 HTTP 提供了一条可靠的
比特传输管道。
tcp 是运输层,http 是应用层。
利用 http 协议传送数据时建立在 tcp/ip 协议的基础之上的,所以发送 http 请求,建立的是 TCP 连接。

操作系统

操作系统参考链接:https://www.cnblogs.com/edisonchou/p/5094066.html

一、线程和进程区别

进程是资源分配最小单位,线程是程序执行的最小单位;
区别如下:
(1)进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段,线程没有独立的地址空间,它使用相同的地址空间共享数据;
(2)CPU 切换一个线程比切换进程花费小;创建一个线程比进程开销小;线程占用的资源要比进程少很多。
(3)线程之间通信更方便,同一个进程下,线程共享全局变量,静态变量等数据,进程之间的通信需要以通信的方式(IPC)进行;(但多线程程序处理好同步与互斥是个难点)
(4)多进程程序更安全,生命力更强,一个进程死掉不会对另一个进程造成影响(源于有独立的地址空间),多线程程序更不易维护,一个线程死掉,整个进程就死掉了(因为共享地址空间);

二、死锁,四个必要条件,怎么避免

如果一组进程中的每一个进程都在等待仅由该组进程中的其它进程才能引发的事件,那么该组进程就是死锁的。

产生死锁的四个必要条件
(1)互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
(2)请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求时,该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
(3)不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。
(4)循环等待条件: 若干进程间形成首尾相接循环等待资源的关系

怎么避免
(1)系统对进程发出每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,如果分配后系统可能发生死锁,则不予分配,否则予以分配。这是一种保证系统不进入死锁状态的动态策略。
(2)破坏不可抢占条件:允许对资源实行抢夺

利用银行家算法避免死锁
所谓银行家算法,是指在分配资源之前先看清楚,资源分配后是否会导致系统死锁。如果会死锁,则不分配,否则就分配。

三、内存分页以及怎么处理内存碎片

内存分页:分页系统的核心在于,将虚拟内存空间和物理内存空间皆划分为大小相同的页面,如4KB、8KB或16KB等,并以页面作为内存空间的最小分配单位,一个程序的一个页面可以存放在任意一个物理页面里。

(1)解决空间浪费碎片化问题
由于将虚拟内存空间和物理内存空间按照某种规定的大小进行分配,这里我们称之为页(Page),然后按照页进行内存分配,也就克服了外部碎片的问题。
(2)解决程序大小受限问题
程序增长有限是因为一个程序需要全部加载到内存才能运行,因此解决的办法就是使得一个程序无须全部加载就可以运行。使用分页也可以解决这个问题,只需将当前需要的页面放在内存里,其他暂时不用的页面放在磁盘上,这样一个程序同时占用内存和磁盘,其增长空间就大大增加了。而且,分页之后,如果一个程序需要更多的空间,给其分配一个新页即可(而无需将程序倒出倒进从而提高空间增长效率)。

内存碎片通常分为内部碎片外部碎片

  1. 内部碎片是由于采用固定大小的内存分区,当一个进程不能完全使用分给它的固定内存区域时就产生了内部碎片,通常内部碎片难以完全避免;
  2. 外部碎片是由于某些未分配的连续内存区域太小,以至于不能满足任意进程的内存分配请求,从而不能被进程利用的内存区域。
    现在普遍采用的段页式内存分配方式就是将进程的内存区域分为不同的段,然后将每一段由多个固定大小的页组成。通过页表机制,使段内的页可以不必连续处于同一内存区域,从而减少了外部碎片,然而同一页内仍然可能存在少量的内部碎片,只是一页的内存空间本就较小,从而使可能存在的内部碎片也较少。

1、虚拟地址的构成
  在分页系统下,一个程序发出的虚拟地址由两部分组成:页面号和页内偏移值,如下图所示:
在这里插入图片描述
例如,对于32位寻址的系统,如果页面大小为4KB,则页面号占20位,页内偏移值占12位。
2、地址翻译:虚拟地址→物理地址(映射)
分页系统的核心是页面的翻译,即从虚拟页面到物理页面的映射(Mapping)。该翻译过程如下伪代码所示:

if(虚拟页面非法、不在内存中或被保护)
{
    陷入到操作系统错误服务程序
}
else
{
    将虚拟页面号转换为物理页面号
    根据物理页面号产生最终物理地址
}

这个翻译是怎么实现的呢?
答:查页表。对于每个程序,内存管理单元MMU都为其保存一个页表,该页表中存放的是虚拟页面到物理页面的映射。每当为一个虚拟页面寻找到一个物理页面之后,就在页表里增加一条记录来保留该映射关系。当然,随着虚拟页面进出物理内存,页表的内容也会不断更新变化。
在这里插入图片描述
页表
页表的根本功能是提供从虚拟页面到物理页面的映射
因此,页表的记录条数与虚拟页面数相同。此外,内存管理单元依赖于页表来进行一切与页面有关的管理活动,这些活动包括判断某一页面号是否在内存里,页面是否受到保护,页面是否非法空间等等。
页表的一个记录所包括的内容如下图所示:
在这里插入图片描述

由于页表的特殊地位,决定了它是由硬件直接提供支持,即页表是一个硬件数据结构。

四、缺页中断及处理

在分页系统中,一个虚拟页面既有可能在物理内存,也有可能保存在磁盘上。如果CPU发出的虚拟地址对应的页面不在物理内存,就将产生一个缺页中断,而缺页中断服务程序负责将需要的虚拟页面找到并加载到内存。缺页中断的处理步骤如下,省略了中间很多的步骤,只保留最核心的几个步骤:
在这里插入图片描述

五、页面调度置换算法中的FiFO、LRU和LFU

然后给了些例子要求解释最近应该要调那个页,简单。
页面置换时挑选页面的目标主要在于降低随后发生缺页中断的次数或概率。

FIFO先进先出 First In First Out,这个没啥好讲的;
LRU最近最少使用页面置换算法(Least Recently Used),选择近期最少访问的页作为被替换页。即首先淘汰最长时间未被使用的页面!
LFU最近最不常用页面置换算法(Least Frequently Used),淘汰一定时期内被访问次数最少的页,在内存保留的都是一些经常访问的对象。对于大部分网站项目,该算法比较适用。

比如,第二种方法的时期T为10分钟,如果每分钟进行一次调页,主存块为3,若所需页面走向为2 1 2 1 2 3 4
注意,当调页面4时会发生缺页中断
若按LRU算法,应换页面1(1页面最久未被使用) 但按LFU算法应换页面3(十分钟内,页面3只使用了一次)
可见LRU是看页面最后一次被使用 到 发生调度的时间
而LFU是看一定时间段内页面被使用的频率!

六、进程间通信方式:信号、管道、消息队列、共享内存

  1. 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
  2. 命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
  3. 消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  4. 共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
  5. 信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  6. 套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
  7. 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

1、信号

信号是Linux系统中用于进程之间通信或操作的一种机制,信号可以在任何时候发送给某一进程,而无须知道该进程的状态。如果该进程并未处于执行状态,则该信号就由内核保存起来,知道该进程恢复执行并传递给他为止。如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式,信号可以在用户空间进程和内核之间直接交互。内核也可以利用信号来通知用户空间的进程来通知用户空间发生了哪些系统事件。信号事件有两个来源:
1)硬件来源,例如按下了cltr+C,通常产生中断信号sigint
2)软件来源,例如使用系统调用或者命令发出信号。最常用的发送信号的系统函数是kill,raise,setitimer,sigation,sigqueue函数。软件来源还包括一些非法运算等操作。

用户进程对信号产生的响应有三种方式:执行默认操作、捕捉信号、忽略信号

1)执行默认操作,linux对每种信号都规定了默认操作。
2)捕捉信号,定义信号处理函数,当信号发生时,执行相应的处理函数。
3)忽略信号,当不希望接收到的信号对进程的执行产生影响,而让进程继续执行时,可以忽略该信号,即不对信号进程作任何处理。
管道允许在进程之间按先进先出的方式传送数据,是进程间通信的一种常见方式。

2、管道
管道是Linux 支持的最初Unix IPC形式之一,具有以下特点:

  1. 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
  2. 匿名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
  3. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

管道分为 pipe(无名管道)fifo(命名管道) 两种,除了建立、打开、删除的方式不同外,这两种管道几乎是一样的。他们都是通过内核缓冲区实现数据传输。
pipe用于相关进程之间的通信,例如父进程和子进程,它通过pipe()系统调用来创建并打开,当最后一个使用它的进程关闭对他的引用时,pipe将自动撤销。
FIFO即命名管道,在磁盘上有对应的节点,但没有数据块——换言之,只是拥有一个名字和相应的访问权限,通过mknode()系统调用或者mkfifo()函数来建立的。一旦建立,任何进程都可以通过文件名将其打开和进行读写,而不局限于父子进程,当然前提是进程对FIFO有适当的访问权。当不再被进程使用时,FIFO在内存中释放,但磁盘节点仍然存在。

管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据:管道一端的进程顺序地将进程数据写入缓冲区,另一端的进程则顺序地读取数据,该缓冲区可以看做一个循环队列,读和写的位置都是自动增加的,一个数据只能被读一次,读出以后再缓冲区都不复存在了。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或写进程是否进入等待队列,当空的缓冲区有新数据写入或慢的缓冲区有数据读出时,就唤醒等待队列中的进程继续读写。

3、消息队列
消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。

消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。

可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。

4、共享内存
共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取错做读出,从而实现了进程间的通信。

采用共享内存进行通信的一个主要好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝,对于像管道和消息队里等通信方式,则需要再内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次:一次从输入文件到共享内存区,另一次从共享内存到输出文件。
共享内存有两种实现方式:1、内存映射 2、共享内存机制

参考连接:https://www.cnblogs.com/LUO77/p/5816326.html

C++程序内存结构
.text: 存放源代码
.rodata: 存放常量
.data: 存放初始化了的全局变量和静态变量
.bss: 存放了未初始化的全局变量和静态变量
.heap: 存放使用malloc, realloc, free等函数控制的变量
.stack: 函数调用时使用栈来保存函数现场,局部变量也存放在栈中
进程间通信的方式:信号量、管道…
内存分页以及怎么处理内存碎片
First-fit,Worst-fit,Best-fit
————————————————
版权声明:本文为CSDN博主「Alva112358」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Alva112358/article/details/93934413

七、linux搜索出log文本中出现次数最多的IP,并且给出次数

算法

一、说一下hashmap这个数据结构

他现在的实现方式是数组+链表+红黑树,通过计算hash,将对象存进hashmap中,当链表的长度大于8,链表进化为红黑树,链表小于6,红黑树退化为链表,这样能防止频繁的进行红黑树的转化,然后红黑树的话通过着色和旋转进行自平衡。

二、进行一次查找,haspmap的时间复杂度是多少

O(1),这个是作为数组的查询复杂度。

三、有一个无限长的整型数组,从小到大排序,非递增。那么怎么找到数组中一个key

模仿计算机网络的慢开始,第一次步长为2,第二次步长为4,第三次为8,持续为2的幂次,大于key时,再在当前位置和当前位置-步长范围内查找。
时间复杂度多少? O(logn)

数据库

一、数据库的四大特征(ACID)

(1)原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。

(2)一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

(3)隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

(4)持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

参考链接:https://www.cnblogs.com/fjdingsd/p/5273008.html

二、如果不考虑事务的隔离性,会发生几种问题

1、脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
2、不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
3、虚读(幻读)
幻读是事务非独立执行时发生的一种现象。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

三、MySQL数据库提供的四种隔离级别

① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。

在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。

四、数据库怎么分页

MySQL 实现分页效果比较简单,只有一个 limit 关键字就可以解决。

五、内连接外连接左连接右连接

一、内连接
关键字:inner join on
说明:组合两个表中的记录,返回关联字段相符的记录,也就是返回两个表的交
集(阴影)部分。

二、左连接(左外连接)
关键字:left join on / left outer join on
它的全称是左外连接,是外连接中的一种。
左(外)连接,左表(a_table)的记录将会全部表示出来,而右表(b_table)只会显示符
合搜索条件的记录。右表记录不足的地方均为 NULL。

三、右连接(右外连接)
关键字:right join on / right outer join on
它的全称是右外连接,是外连接中的一种。
与左(外)连接相反,右(外)连接,左表(a_table)只会显示符合搜索条件的记录,而
右表(b_table)的记录将会全部表示出来。左表记录不足的地方均为 NULL。

四、全外连接(FULL JOIN 或 FULL OUTER JOIN)
完整外部联接返回左表和右表中的所有行。

六、Group By 语句

Group By 语句从英文的字面意义上理解就是“根据(by)一定的规则进行分组(Group)”。
作用:通过一定的规则将一个数据集划分成若干个小的区域,然后针对若干个小区域进行数据处理。
注意:group by 是先排序后分组

七、聚合函数有什么特点?

聚合函数对一组值执行计算并返回单一的值。
除了 COUNT 以外,聚合函数忽略空值。
聚合函数经常与 SELECT 语句的 GROUP BY 子句一同使用。
所有聚合函数都具有确定性。任何时候用一组给定的输入值调用它们时,都返回相同的值。
1、求个数/记录数/项目数等:count()
2、求某一列平均数 :avg()
3、求总和,总分等:sum() --必须为数字列
4、求最大值,最高分,最高工资等:max()

在实际应用中,聚合函数常和分组函数 group by 结合使用,用来查询.where 子句的作用对象一般只是行,用来作为过滤数据的条件。

标量函数:只能对单个的数字或值进行计算。主要包括字符函数、日期/时间函数、数值函数和转换函数这四类。

八、索引的作用

创建索引可以大大提高系统的性能。
第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二,可以大大加快 数据的检索速度,这也是创建索引的最主要的原因。
第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

九、怎么建立索引?

学生学号姓名年级成绩老师入学时间 可以根据什么来建立索引

建议将学号建为主键。主键 建个聚集索引 其他两个建立非聚集的。

Java基础

https://www.jianshu.com/p/01f0cb5d4e67

什么是线程局部变量?

线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java 提供 ThreadLocal 类来支持线程局部变量,是一种实现线程安全的方式。但是在管理环境下(如 web 服务器)使用线程局部变量的时候要特别小心,在这种情况下,工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放,Java 应用就存在内存泄露的风险。

Java 中 sleep 方法和 wait 方法的区别?

虽然两者都是用来暂停当前运行的线程,但是 sleep() 实际上只是短暂停顿,因为它不会释放锁,而 wait() 意味着条件等待,这就是为什么该方法要释放锁,因为只有这样,其他等待的线程才能在满足条件时获取到该锁。

什么是不可变对象?Java 怎么创建?

不可变对象(immutable object)
不可变对象指对象一旦被创建,状态就不能再改变。任何修改都会创建一个新的对象,如 String、Integer及其它包装类。详情参见答案,一步一步指导你在 Java 中创建一个不可变的类。

怎么将 byte 转换为 String?

可以使用 String 接收 byte[] 参数的构造器来进行转换,需要注意的点是要使用的正确的编码,否则会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不同。

哪个类包含 clone 方法?是 Cloneable 还是 Object?

clone 方法在 object 类中定义。
java.lang.Cloneable 是一个标示性接口,不包含任何方法,并且需要知道 clone() 方法是一个本地方法,这意味着它是由 c 或 c++ 或 其他本地语言实现的。

a = a + b 与 a += b 的区别

+= 隐式的将加操作的结果类型强制转换为持有结果的类型。如果两这个整型相加,如 byte、short 或者 int,首先会将它们提升到 int 类型,然后在执行加法操作。如果加法操作的结果比 a 的最大值要大,则 a+b 会出现编译错误,但是 a += b 没问题,如下:
byte a = 127;
byte b = 127;
b = a + b; // error : cannot convert from int to byte
b += a; // ok
(译者注:这个地方应该表述的有误,其实无论 a+b 的值为多少,编译器都会报错,因为 a+b 操作会将 a、b 提升为 int 类型,所以将 int 类型赋值给 byte 就会编译出错)

Java 中的构造器链是什么?

当你从一个构造器中调用另一个构造器,就是Java 中的构造器链。这种情况只在重载了类的构造器的时候才会出现。

JVM和GC

Serial 与 Parallel GC之间的不同之处?

Serial 与 Parallel 在GC执行的时候都会引起 stop-the-world。它们之间主要不同 serial 收集器是默认的复制收集器,执行 GC 的时候只有一个线程,
而 parallel 收集器使用多个 GC 线程来执行。

WeakReference 与 SoftReference的区别?

虽然 WeakReference 与 SoftReference 都有利于提高 GC 和 内存的效率,但是 WeakReference ,一旦失去最后一个强引用,就会被 GC 回收,
而软引用虽然不能阻止被回收,但是可以延迟到 JVM 内存不足的时候。

WeakHashMap 是怎么工作的?

WeakHashMap 的工作与正常的 HashMap 类似,但是使用弱引用作为 key,意思就是当 key 对象没有任何引用时,key/value 键值对将会被回收。

JVM 选项 -XX:+UseCompressedOops 有什么作用?为什么要使用?

当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从 32 位增加到了 64 位,因此堆内存会突然增加,差不多要翻倍。这也会对 CPU 缓存(容量比内存小很多)的数据产生不利的影响。因为,迁移到 64 位的 JVM 主要动机在于可以指定最大堆大小,通过压缩 OOP 可以节省一定的内存。通过 -XX:+UseCompressedOops 选项,JVM 会使用 32 位的 OOP,而不是 64 位的 OOP。

JRE、JDK、JVM 及 JIT 之间有什么不同?

JRE 代表 Java 运行时(Java run-time),是运行 Java 引用所必须的。
JDK 代表 Java 开发工具(Java development kit),是 Java 程序的开发工具,如 Java 编译器,它也包含 JRE。
JVM 代表 Java 虚拟机(Java virtual machine),它的责任是运行 Java 应用。
JIT 代表即时编译(Just In Time compilation),当代码执行的次数超过一定的阈值时,会将 Java 字节码转换为本地代码,如主要的热点代码会被转换为本地代码,这样有利大幅度提高 Java 应用的性能。

解释 Java 堆空间及 GC?

当通过 Java 命令启动 Java 进程的时候,会为它分配内存。内存的一部分用于创建堆空间,当程序中创建对象的时候,就从对空间中分配内存。
GC 是 JVM 内部的一个进程,回收无效对象的内存用于将来的分配。

Java 中堆和栈有什么区别?

JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。
栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。

hashCode() 的作用?a.equals(b) 有何关系?

hashCode() 方法是相应对象整型的 hash 值。它常用于基于 hash 的集合类,如 Hashtable、HashMap、LinkedHashMap等等。它与 equals() 方法关系特别紧密。根据 Java 规范,两个使用 equal() 方法来判断相等的对象,必须具有相同的 hash code。

final、finalize 和 finally 的不同之处?

final 是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变
finalize() 方法是在对象被回收之前调用的方法,给对象自己最后一个复活的机会,但是什么时候调用 finalize 没有保证。
finally 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。

Java 中的编译期常量是什么?使用它又什么风险?

公共静态不可变public static final )变量也就是我们所说的编译期常量,这里的 public 可选的。实际上这些变量在编译时会被替换掉,因为编译器知道这些变量的值,并且知道这些变量在运行时不能改变。这种方式存在的一个问题是你使用了一个内部的或第三方库中的公有编译时常量,但是这个值后面被其他人改变了,但是你的客户端仍然在使用老的值,甚至你已经部署了一个新的jar。为了避免这种情况,当你在更新依赖 JAR 文件时,确保重新编译你的程序。

List、Set、Map 和 Queue 之间的区别(答案)

List 是一个有序集合,允许元素重复。它的某些实现可以提供基于下标值的常量访问时间,但是这不是 List 接口保证的。
Set 是一个无序集合。

poll() 方法和 remove() 方法的区别?

poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。

Java 中 LinkedHashMap 和 PriorityQueue 的区别

PriorityQueue 保证最高或者最低优先级的的元素总是在队列头部,但是 LinkedHashMap 维持的顺序是元素插入的顺序。
当遍历一个 PriorityQueue 时,没有任何顺序保证,但是 LinkedHashMap 课保证遍历顺序是元素插入的顺序。

ArrayList 与 LinkedList 的区别?

ArrrayList 底层的数据结构是数组,支持随机访问
而 LinkedList 的底层数据结构书链表,不支持随机访问。
使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。

用哪两种方式来实现集合的排序?

可以使用无序集合,如 TreeSet 或 TreeMap,你也可以使用有顺序的的集合,如 list,然后通过 Collections.sort() 来排序。

Java 中怎么打印数组?

你可以使用 Arrays.toString() 和 Arrays.deepToString() 方法来打印数组。由于数组没有实现 toString() 方法,所以如果将数组传递给 System.out.println() 方法,将无法打印出数组的内容,但是 Arrays.toString() 可以打印每个元素。

Java 中的 LinkedList 是单向链表还是双向链表?

是双向链表,你可以检查 JDK 的源码。在 Eclipse,你可以使用快捷键 Ctrl + T,直接在编辑器中打开该类。

Java 中的 TreeMap 是采用什么树实现的?

Java 中的 TreeMap 是使用红黑树实现的。

Hashtable 与 HashMap 有什么不同之处?(答案)

这两个类有许多不同的地方,下面列出了一部分:
a) Hashtable 是 JDK 1 遗留下来的类,而 HashMap 是后来增加的。
b)Hashtable 是同步的,比较慢,但 HashMap 没有同步策略,所以会更快。
c)Hashtable 不允许有个空的 key,但是 HashMap 允许出现一个 null key。

Java 中的 HashSet,内部是如何工作的?

HashSet 的内部采用 HashMap来实现。由于 Map 需要 key 和 value,所以所有 key 的都有一个默认 value。类似于 HashMap,HashSet 不允许重复的 key,只允许有一个null key,意思就是 HashSet 中只允许存储一个 null 对象。

写一段代码在遍历 ArrayList 时移除一个元素?

public class test{
	public static void main(String[] args){
		ArrayList<Sting> aList = new ArrayList<String>();
		aList.add("a");
		aList.add("ab");  
        aList.add("abc");  
        aList.add("abcr");  
        aList.add("abc");  
        aList.add("abcf");  
        aList.add("abc");  
        aList.add("abdc");  
		Itrator<Sting> it = aList.iterator();
		while(it.hasNext()){
			if(it.next().equals("abc"))
				it.remove();
		}
	}
}

能自己写一个容器类,然后使用 for-each 循环码?

可以,你可以写一个自己的容器类。如果你想使用 Java 中增强的循环来遍历,你只需要实现 Iterable 接口。如果你实现 Collection 接口,默认就具有该属性。

ArrayList 和 HashMap 的默认大小是多数?

在 Java 7 中,ArrayList 的默认大小是 10 个元素,HashMap 的默认大小是16个元素(必须是2的幂)。

说下java的GC

答:现在是分代收集方式,首先进行垃圾对象的判断,判断的话有两种方法:引用计数和可达性分析。
引用计数就是有一处引用了该对象就计数+1,当计数器为0时,代表没有地方引用他,可以回收,但是没法解决循环引用问题,现在主流虚拟机都不用这种办法。
可达性分析是选了一些对象作为GCROOTS,当从gcroots出发没有引用线时可回收。
垃圾回收的话就是有三种,标记清除标记整理复制算法

*一、SSM框架的理解

SSM框架是spring MVC ,spring和mybatis框架的整合,是标准的MVC模式。
将整个系统划分为 表现层,controller层,service层,DAO层 四层

使用spring MVC负责请求的转发和视图管理

spring实现业务对象管理,mybatis作为数据对象的持久化引擎

SpringMVC的原理

1.客户端发送请求到DispacherServlet(分发器)

2.由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller

3.Controller调用业务逻辑处理后,返回ModelAndView

4.DispacherSerclet查询视图解析器,找到ModelAndView指定的视图

5.视图负责将结果显示到客户端
在这里插入图片描述
————————————————
版权声明:本文为CSDN博主「bieleyang」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/bieleyang/article/details/77862042

*一、谈谈对spring的理解

Spring:我们平时开发接触最多的估计就是IOC容器,它可以装载bean(也就是我们Java中的类,当然也包括service dao里面的),有了这个机制,我们就不用在每次使用这个类的时候为它初始化,很少看到关键字new。另外spring的aop,事务管理等等都是我们经常用到的。

1.spring的工作原理
spring 是按照设计模式精心打造的,它实现了工厂模式的工厂类,这个类名为BeanFactory(接口),在程序中通常使用它的子类ApplicationContext(也是接口)。

spring的核心是IOC(反转控制)容器,IOC也是一种编程思想,用于实现模块之间的解耦,在Spring中它的作用是对对象的创建,维护和销毁等生命周期的控制。IOC:把对象的创建、初始化、销毁交给spring来管理,而不是由开发者控制,实现控制反转。

spring是一个大的工厂类,spring的特点就是基于配置,在其配置文件中通过元素来创建实例对象。

根据业务逻辑来看,对象经常不是独立的,一个对象的创建往往涉及另一个对象的创建,当然这个对象也要由IOC容器负责,负责的方式就是依赖注入DI,通过反射机制实现。有三种注入方式:(1)接口注入(2)构造器注入(3)Setter方法注入。

2.spring的核心技术
spring的核心技术有:IOC,AOP

java 的 高级特性:反射机制,代理

AOP:面向切面编程,系统中有很多各不相干的类的方法,在这众多方法中加入某种系统功能的代码,如加入日志,权限判断等,AOP可以实现横切关注点(如日志,安全,缓存和事务管理)与他们所影响的对象之间的解耦。

实现AOP 功能采用的是代理技术,调用代理类,代理类与目标类具有相同的方法声明。

AOP 在spring中主要表现在两个方面:提供声明式的事务管理 、spring支持用户自定义切面。

spring AOP的使用在另外一位同学的博客中可以看到:Java Spring AOP用法

AOP主要包括通知(Advice)切点(PointCut)连接点(JoinPoint)

下面贴一段在springboot 中使用AOP的代码:

        <!-- aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

@Aspect
@Component
public class ControllerInterceptor {
 
    private final Logger logger = LogManager.getLogger(this.getClass());
    @Pointcut("execution(public * com.example.homework.controller..*(..))")
    public void controllerMethodPointcut(){}
 
    @Before("controllerMethodPointcut()") //指定拦截器规则
    public Object interceptor(JoinPoint jp){
        MethodSignature signature = (MethodSignature) jp.getSignature();
        Method method = signature.getMethod(); //获取被拦截的方法
        String methodName = method.getName(); //获取被拦截的方法名
        logger.info("interceptor ***************************");
        logger.info("methodName: "+methodName);
        return null;
    }
}
2018-08-21 11:07:22.906  INFO 10392 --- [nio-8088-exec-1] a.s.s.m.AbstractValidatingSessionManager : Enabling session validation scheduler...
2018-08-21 11:07:22.987  INFO 10392 --- [nio-8088-exec-1] c.e.h.controller.ControllerInterceptor   : interceptor ***************************
2018-08-21 11:07:22.987  INFO 10392 --- [nio-8088-exec-1] c.e.h.controller.ControllerInterceptor   : methodName: loginIn

3.spring 的优缺点
Spring 的核心概念是IOC和AOP,这两个核心服务的对象算是bean(POJO),定位是一个轻量级的框架,但是随着他的发展变得很庞大,我们称它为spring 全家桶。

它具备以下优点:

  1. spring中避免了关键字new造成的耦合问题。
  2. spring本身就是一个工厂,不需要再编写工厂类了。
  3. spring不需要进行明确的引用关系的传递,直接通过配置完成
  4. 所有框架几乎都可以在spring中整合在一起使用。
  5. spring编程=factory设计模式+proxy设计模式

当然,它的缺点也是不少的:
spring基于大量的xml 配置文件,使得我们花了大量的时间放在配置上,拖慢了开发的进度,springboot 问世后,提倡代码优于配置解决了这个问题。

spring 的内容太庞大,随便打断点查看的时候会出现十几二十层代码,阅览性不强,在实际开发的过程中spring的角色更像是胶水一样,充当整合各种技术的角色,同时作为bean的容器。

————————————————
版权声明:本文为CSDN博主「花猪秀儿」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wolf_goat/article/details/81874862

*二、SSM开发的流程

正向从entity到dao 到mapper到service到controller。
1、首先根据业务,确定实体类(一般与数据库的表一一对应)和封装类(Controller返回的对象类,一般是实体类的部分字段或是实体类的List或者业务衍生出的字段的集合)
2、根据第一步的封装类,编写dao以及对应的mapper,dao的逻辑就是为了产生封装类的属性(部分属性可直接产生,还有一部分属性需要到service层对数据处理才能产生)。
3、根据业务需求,编写service层,service层对dao层产生的数据进行处理,把封装类的属性全部设置进去返回。
4、最后编写controller层代码,需提前与前端确定好URL规范,调用service得到返回的封装类,加上@ResponseBody注解返回

我们把所有的dao和service都交由spring来管理,在spring-mybatis.xml文件中,我们指定了dao的位置,所以dao层不需要手动加注解,但是service,controller层需要我们手动加上注解@Service(此注解加在Service的实现类上) @Controller。
——————————————————————————————————
参考:https://blog.csdn.net/qq_33591903/article/details/81101975

*三、MyBatis及工作原理

mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。

原理图如下:
在这里插入图片描述
(1)mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件(也可以用Java文件配置的方式,需要添加@Configuration)来构建SqlSessionFactory(SqlSessionFactory是线程安全的);
(2)SqlSessionFactory的实例直接开启一个SqlSession,再通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交,之后关闭SqlSession。

说明:SqlSession是单线程对象,因为它是非线程安全的,是持久化操作的独享对象,类似jdbc中的Connection,底层就封装了jdbc连接。

详细流程如下
1、加载mybatis全局配置文件(数据源、mapper映射文件等),解析配置文件,MyBatis基于XML配置文件生成Configuration,和一个个MappedStatement(包括了参数映射配置、动态SQL语句、结果映射配置),其对应着<select | update | delete | insert>标签项。
2、SqlSessionFactoryBuilder通过Configuration对象生成SqlSessionFactory,用来开启SqlSession。
3、SqlSession对象完成和数据库的交互:

  • a、用户程序调用mybatis接口层api(即Mapper接口中的方法)
  • b、SqlSession通过调用api的Statement ID找到对应的MappedStatement对象
  • c、通过Executor(负责动态SQL的生成和查询缓存的维护)将MappedStatement对象进行解析,sql参数转化、动态sql拼接,生成jdbc Statement对象
  • d、JDBC执行sql。
  • e、借助MappedStatement中的结果映射关系,将返回结果转化成HashMap、JavaBean等存储结构并返回。

————————————————————————————————
学习参考网站:
[1] http://c.biancheng.net/view/4304.html
[2]https://blog.csdn.net/u014745069/article/details/80788127

cookie 和session 的区别:

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、所以个人建议:
将登陆信息等重要信息存放为SESSION
其他信息如果需要保留,可以放在COOKIE中

*Maven项目的生命周期

开始—>Validate验证—>Compile编译—>Test测试—>Package打包—>Verify检查—>Install安装—>Deploy部署—>开始

发布了88 篇原创文章 · 获赞 141 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_37717494/article/details/104940026