武林外传积分号私服只能开2个号'在开多一个就提示无法加载游戏数据文件'用elementclient也不行

从原理上TCP的优势有:

TCP最糟糕的特性是它对阻塞的控制。一般来说TCP假定丢包是由于网络带宽不够造成的,所以发生这种情况的时候TCP就会减少发包速度

在3G或WiFi下一个數据包丢失了,你希望的是立马重发这个数据包然而TCP的阻塞机制却完全是采用相反的方式来处理!

而且没有任何办法能够绕过这个机制,因为这是TCP协议构建的基础这就是为什么在3G或者WiFi环境下,ping值能够上升到1000多毫秒的原因

UDP相对TCP来说既简单又困难。

举个例子来说UDP是基于數据包构建,这意味着在某些方面需要你完全颠覆在TCP下的观念UDP只使用一个socket进行通信,不像TCP需要为每一个客户端建立一个socket连接这些都是UDP非常不错的地方。

但是大多数情况下你需要的仅仅是一些连接的概念罢了,一些基本的包序功能以及所谓的连接可靠性。可惜的是這些功能UDP都没有办法简单的提供给你,而你使用TCP却都可以免费得到

使用TCP失败的地方:

可靠的UDP也是有延迟的,但是由于它是在UDP的基础之上建立的通信协议所以可以通过多种方式来减少延迟,不像TCP所有的东西都要依赖于TCP协议本身而无法被更改

魔兽世界以及其他的一些游戲是怎么处理延迟问题的呢

一些类似发起攻击动作和释放技能特效就能够在没有收到服务器确认的情况下就直接执行,比如展现冰冻技能的效果就可以在服务器没有返回数据前在客户端就做出来

客户端直接开始进行计算而不等待服务端确认是一种典型的隐藏延迟的技术。

这也意味着我们到底是使用TCP还是UDP取决于我们能否隐藏延迟。

一个采用TCP的游戏必须能够处理好突发的延迟问题(纸牌客户端就很典型對突发性的一秒的延迟,玩家也不会产生什么抱怨)或者是拥有缓解延迟问题的好方法

如果你运行的是一个无法使用任何减缓延迟措施嘚游戏呢?玩家对玩家的动作类游戏通常就属于这个范畴但是这也不仅仅限于动作类游戏。

一种常见的操作是你快速的移动你的角色通过一张充满战争迷雾的世界地图,但是一旦你探索过迷雾就会被打开。

为了确保游戏的规则防止玩家作弊,服务器只能显示玩家当湔位置附近的信息这意味着不像魔兽世界,玩家无法在没有得到服务器响应的情况下做出完整的动作。战争迷雾的探开必须依靠服务器传过来的响应

而当出现丢包时,由于拥塞控制的原因服务器的响应速度就从100-150毫秒上升到毫秒

没有任何办法可以绕过TCP的这个设置来避開这个问题。

我们替换了TCP的代码用了自定义的可靠的UDP来实现,把大量的丢包产生的延迟降到了仅仅只有50毫秒甚至比以前TCP不丢包的情况┅个来回的延迟还要小。当然这只可能建立在UDP之上,这样我们才对可靠性拥有完全的掌控力

可靠的UDP一点也不像TCP,要去实现一个特殊的阻塞控制事实上,这也是你使用可靠UDP代替TCP的最大的原因避免TCP的阻塞控制。

那么到底是用UDP还是TCP呢

  • 如果是由客户端间歇性的发起无状态嘚查询,并且偶尔发生延迟是可以容忍那么使用HTTP/HTTPS吧。
  • 如果客户端和服务器都可以独立发包但是偶尔发生延迟可以容忍(比如:在线的紙牌游戏,许多MMO类的游戏)那么使用TCP长连接吧。
  • 如果客户端和服务器都可以独立发包而且无法忍受延迟(比如:大多数的多人动作类遊戏,一些MMO类游戏)那么使用UDP吧。

死锁条件怎么解决?具体形容一下怎么个情况是死锁

互斥:每个资源要么已经分配给了一个进程偠么就是可用的。
占有和等待:已经得到了某个资源的进程可以再请求新的资源

不可抢占:已经分配给一个进程的资源不能强制性地被搶占,它只能被占有它的进程显式地释放环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源

鸵鸟策略死锁检测与死锁恢复死锁预防死锁避免

  1. 带宽优化及网络连接的使用,HTTP1.0中存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分而服务器却将整个对象送过来了,并且不支持断点续传功能HTTP1.1则在请求头引入了range头域,它允许只请求资源嘚某个部分即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接

  2. 错误通知的管理,在HTTP1.1中新增了24个错误状态响應码如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

  3. Host头处理在HTTP1.0中认为每台服务器嘟绑定一个唯一的IP地址,因此请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展在一台物理服务器上可以存在多个虚擬主机(Multi-homed Web Servers),并且它们共享一个IP地址HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)

  4. 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点

HTTP/1.x 实现简单是以牺牲性能为代价的:
客户端需要使用多个连接才能实现并发和缩短延遲;
不会压缩请求和响应首部,从而导致不必要的网络流量;
不支持有效的资源优先级致使底层 TCP 连接的利用率低下。

HTTP/2.0 将报文分成 HEADERS 帧DATA 帧(一个报文拆分成两部分分别传送)它们都是二进制格式的,HTTP1.x的解析是基于文本。

在通信过程中,只会有一个 TCP 连接存在它承载了任意數量的双向数据流(Stream)。

消息(Message)是与逻辑请求或响应对应的完整的一系列帧
帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错發送然后再根据每个帧头的数据流标识符重新组装。

HTTP/2.0 在客户端请求一个资源时会把相关的资源一起发送给客户端,客户端就不需要再佽发起请求了例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端

HTTP/1.1 的首部带有大量信息,而且每次都要重复发送
HTTP/2.0 偠求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免了重复传输
不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩

HTTP 有以下安全性问题:
使用明文进行通信,内容可能会被窃听;
不验证通信方的身份通信方的身份有可能遭遇伪装;
无法证明报文的完整性,报文有可能遭篡改

缺点:无法安全地将密钥传输给通信方

非对称密钥加密又称公开密钥加密(Public-Key Encryption),加密和解密使用不同的密鑰
公开密钥所有人都可以获得通信发送方获得接收方的公开密钥之后就可以使用公开密钥进行加密,接收方收到通信内容后使用私囿密钥解密
非对称密钥除了用来加密,还可以用来进行签名因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签洺通信接收方使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确
优点:可以更安全地将公开密钥传输给通信发送方;

真正使用时,实际上是先用发送方得到接收方非对称密钥加密的公开密钥然后用这个公开密钥将其对称密钥进行加密,接受方收到后解密得到对称密钥之后就以这个对称密钥进行通信。

通过使用 证书 来对通信方进行认证
数字证书认证机构(CA,Certificate Authority)是客户端与服务器双方都可信赖的第三方机构
服务器的运营人员向 CA 提出公开密钥的申请,CA 在判明提出申请者的身份之后会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥并将该公开密钥放入公开密钥证书后绑定在一起。
进行 HTTPS 通信时服务器会把证书发送给客户端。客户端取得其中的公开密钥之后先使用数字签名进行验证,如果验证通过就可以开始通信了

 首先看为什么要认证?

细心的人可能已经注意箌了如果使用非对称加密算法我们的客户端A,B需要一开始就持有公钥要不没法开展加密行为啊。

这下我们又遇到新问题了,如何让A、B客户端安全地得到公钥

client获取公钥最最直接的方法是服务器端server将公钥发送给每一个client用户,但这个时候就出现了公钥被劫持的问题如上圖,client请求公钥在请求返回的过程中被×××劫持,那么我们将采用劫持后的假秘钥进行通信则后续的通讯过程都是采用假秘钥进行,数據库的风险仍然存在在获取公钥的过程中,我们又引出了一个新的话题:如何安全的获取公钥并确保公钥的获取是安全的, 那就需要鼡到终极武器了:SSL 证书(需要购买)和CA机构

在第 ② 步时服务器发送了一个SSL证书给客户端SSL 证书中包含的具体内容有证书的颁发机构、有效期、公钥、证书持有者、签名,通过第三方的校验保证了身份的合法解决了公钥获取的安全性(中间人的公钥没有第三方的保证)

以浏覽器为例说明如下整个的校验过程:

(1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验

(2)浏览器开始查找操作系统Φ已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对用于校验证书是否为合法机构颁发 

(3)如果找不到,浏览器就會报错说明服务器发来的证书是不可信任的。

(4)如果找到那么浏览器就会从操作系统中取出  颁发者CA  的公钥,然后对服务器发来的证書里面的签名进行解密

(5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值将这个计算的hash值与证书中签名做对比

(6)对比结果一致,则证明服务器发来的证书合法没有被冒充

(7)此时浏览器就可以读取证书中的公钥,用于后续加密了

图里的DATA相当于要发送的公钥

首先服务器向CA请求,CA对这个公钥进行数字签名然后放入证书。

服务器将这个证书发送给对端对端接收到后首先判断CA是不是合法机构,如果是就拿出一个CA的公钥对签名进行解密,解密得到数字签名然后将数据(也就是公钥)进行hash,将得到的结果与数字签名进行对比如果相同则证明合法,就可以用这个公钥进行对称密钥的加密了

SSL 提供报文摘要功能来进行完整性保护。
HTTP 也提供了 MD5 报文摘要功能但不是安铨的。例如报文内容被篡改之后同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改
HTTPS 的报文摘要功能之所以安全,是因为它结合叻加密和认证这两个操作试想一下,加密之后的报文遭到篡改之后,也很难重新计算报文摘要因为无法轻易获取明文。

strcpy与memcpy不同存在於:strcpy只复制字符串而memcpy可以复制任何内容(字符数组、结构体、类)等。strcpy不需要指定长度由结束符”\0”而结束战斗的memcpy由第三个参数所决萣

把src所指由NULL结束的字符串复制到dest所指的数组中

src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

strcpy只是复制字符串但不限淛复制的数量。很容易造成缓冲溢出也就是说,不过dest有没有足够的空间来容纳src的字符串它都会把src指向的字符串全部复制到从dest开始的内存

当dst在src和src的结尾之间时会出现问题:

这是由于src后面准备复制到dst中的数据被dst所覆盖的原因

不考虑内存重叠的stcpy的实现:

因此对于这时,要从后往前拷贝复制前统计长度,用长度来控制停止

else //正常情况,从低地址开始复制

将src逐字节拷贝到dst拷贝n个字节

memcpy不会添加'\0',只是机械地拷贝,甴n来决定停止

问题:同样,当出现内存重叠时如dst在src和src+strlen(stc)+1中间时:src后面还没有复制到dst中的数据会被覆盖掉

解决办法也是从高地址往低地址拷貝

memmove用于拷贝字节,如果目标区域和源区域有重叠的话memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源内容會被更改但是当目标区域与源区域没有重叠则和memcpy函数功能相同。

函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 注意,ch只能取-1囷0这两个值。因为是逐字节赋值的比如对一个int数,如果ch=1最后相当于0x而不是想象中的每一位都是1.

而-1是可以的,这是因为赋值是取的ch的后8位进行复制而-1的后八位是。

strncpy通过size来控制复制的结束这个size是源字符串from的大小,这便保证了字符复制的安全性这是一种强制性的安全措施,同样它有似乎不可避免的会产生下面的问题:

1.strncpy不能保证目标字符串to以'\0'结尾这种情况发生在源字符串from长度大于目标字符串to的长度。由於from大于to的长度因此会覆盖掉to的'\0',而如果指定的长度没有涉及到from的'\0',则会无'\0';

2.源字符串from较小而目标字符串to较大,将会用大量'\0'填充剩余的空间from较小,仍会复制size个字节但缺少的字节由'\0'补齐

功能: 在已知dest缓冲区大小并不会造成缓冲区溢出前提下,将src地址开始的字符串复制到以dest开始的地址空间

返回值:src字符串的大小

函数参数:参数dest为目的字符串开始的指针src为源字符串的开始地址,参数size代表dest字符串的大小,也就是缓沖区大小

//这句判断大赞起码有效防止源字符串的越界问题

1).线性探测再散列:

3).伪随机探测再序列

换其他的哈希方法来计算地址,直到可以苼成不冲突的哈希

拉链法中链表太长了应该如何解决

当bucket中有3/4的有负载时要进行rehash,重建一个2倍大小的bucket数组,由于重建后hash长度变了所以要重噺对其中的值进行哈希并开链。

当链表长度超过8要将链表转为红黑树。

理想情况下随机hashCode算法下所有bin中节点的分布频率会遵循泊松分布峩们可以看到,一个bin中链表长度达到8个元素的概率为0.几乎是不可能事件

而且n=8时,8与log28=3差距不算太大综合考虑建树产生的消耗。

Memory)位于CPU与內存之间的临时存储器它的容量比内存小但交换速度快。在缓存中的数据是内存中的一小部分但这一小部分是短时间内CPU即将访问的,當CPU调用大量数据时就可避开内存直接从缓存中调用,从而加快读取速度由此可见,在CPU中加入缓存是一种高效的解决方案这样整个内存储器(缓存+内存)就变成了既有缓存的高速度,又有内存的大容量的存储系统了缓存对CPU的性能影响很大,主要是因为CPU的数据交换顺序囷CPU与缓存间的带宽引起的

缓存的工作原理是当CPU要读取一个数据时,首先从缓存中查找如果找到就立即读取并送给CPU处理;如果没有找到,就用相对慢的速度从内存中读取并送给CPU处理同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进荇不必再调用内存。

正是这样的读取机制使CPU读取缓存的命中率非常高(大多数CPU可达90%左右)也就是说CPU下一次要读取的数据90%都在缓存中,呮有大约10%需要从内存读取这大大节省了CPU直接读取内存的时间,也使CPU读取数据时基本无需等待总的来说,CPU读取数据的顺序是先缓存后内存

如何选取N个不重复的随机数?复杂度要低(洗牌算法)

第一次随机选中200,将200与44交换

下一次就只在0~4间选取

在下一次就只在0~3件选取

第二次嘚概率为,第一次没选中这个数的概率也就是(n-1)/n;乘上第二次被选中的概率,也就是1/(n-1),为1/n

逆波兰表达式的转换与求值

'('与')'有最高的优先级;*,/有佽级的优先级;+,-最低优先级

遇到的运算符如果比栈顶的运算符优先级低,且栈顶不为(,则输出栈顶内的元素直到栈顶的优先级小于当前运算苻然后将运算符push进栈:因为当前的运算符优先级低,所以数字应该优先与优先级高的向结合

遇到')',则输出栈内元素直到栈顶为(,再将(pop掉。

朂后如果栈不为空,则将栈内元素依次输出

二层三层转发(ping的过程)

首先,Ping命令会构建一个固定格式的ICMP请求数据包然后由ICMP协议将这個数据包连同地址“192.168.0.5”一起交给IP层协议(和ICMP一样,实际上是一组后台运行的进程)IP层协议将以地址“192.168.0.5”作为目的地址,本机IP地址作为源哋址加上一些其他的控制信息,构建一个IP数据包并想办法得到192.168.0.5的MAC地址(物理地址,这是数据链路层协议构建数据链路层的传输单元——帧所必需的)以便交给数据链路层构建一个数据帧。关键就在这里IP层协议通过机器B的IP地址和自己的子网掩码,发现它跟自己属同一網络就直接在本网络内查找这台机器的MAC,如果以前两机有过通信在A机的ARP缓存表应该有B机IP与其MAC的映射关系,如果没有就发一个ARP请求广播,得到B机的MAC一并交给数据链路层。后者构建一个数据帧目的地址是IP层传过来的物理地址,源地址则是本数据机的物理地址还要附加上一些控制信息,依据以太网的介质访问规则将它们传送出去。主机B收到这个数据帧后先检查它的目的地址,并和本机的物理地址對比如符合,则接收;否则丢弃接收后检查该数据帧,将IP数据包从帧中提取出来交给本机的IP层协议。同样IP层检查后,将有用的信息提取后交给ICMP协议后者处理后,马上构建一个ICMP应答包发送给主机A,其过程和主机A发送ICMP请求包到主机B一模一样

PC1准备向PC2发送数据包

(1)PC1檢查报文的目的IP地址,发现和自己不在同一网段则需要进行三层转发,通过网关转发报文信息;

(2)PC1检查自己的ARP表发现网关的MAC地址不茬自己的ARP表里;

(6) PC1学习到Router(网关)的mac地址,发出报文此时源ip、目的ip不变,目的mac为Router(网关)的mac;

(8)Router(网关)收到报文发现是三层报攵(原因是报文的目的mac是自己的mac);

(9)Router(网关)检查自己的路由表(FIB),发现目的ip在自己的直连网段;

(10)Router检查自己的arp表如果发现有與目的ip对应的mac地址则直接封装报文(目的ip、源ip不变,目的mac为查arp表所得mac)发送给PC2;

(11)如果查ARP表没有得到与目的ip对应MAC则重复(3)发arp请求;

(12)PC2收到ARP广播报文,发现目的IP是自己的IP于是给Router发送ARP应答报文。报文中会附上自己的mac地址;

(13)Router收到应答报文后目的mac改为PC2的mac,然后向PC2发送数据帧;

如何处理的topk问题如果突然有大量玩家,需要找大量的topok怎么办

第一、100000名实时遍历系统一定承受不了或者说这样做代价太大那麼可以首先遍历一遍,挑选出战斗力最高的1000名然后后面只遍历这1000名就可以了,因为前500名大概率都是前一千名产生的减少系统开销。

第②、为了防止某些玩家充钱了大幅提升战斗力,那么可以设置一个阈值如果某个玩家战斗力增加速度超过阈值,那么这个玩家也应该納入实时排序过程中

第三、最后100000名玩家的战斗力可以定期在服务器压力不大的时候,比如休服时期或者夜间做整体排序,以便校验数據的准确性

C++指针和引用的参数传递区别

1.指针参数传递本质上是值传递,它所传递的是一个地址值值传递的特点是,被调函数对形式参數的任何操作都是作为局部变量进行的不会影响主调函数的实参变量的值(形参指针变了,实参指针不会变)

2.引用参数传递过程中,被调函数的形式参数也作为局部变量在栈中开辟了内存空间但是这时存放的是由主调函数放进来的实参变量的地址.因此,被调函数对形參的任何操作都会影响主调函数中的实参变量

3.从编译的角度来讲,程序在编译时分别将指针和引用添加到符号表上符号表中记录的是變量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值引用在符号表上对应的地址值为引用对象的地址值(与实参名字不同,地址相同)符号表生成之后就不会再改,因此指针可以改变其指向的对象(指针变量中的值可以改)而引用对象則不能修改。

1. 申请的内存所在位置

new操作符从自由存储区(free store)上为对象动态分配内存空间而malloc函数从堆上动态分配内存

new在静态存储区上分配內存

//静态区,栈区堆区

new操作符内存分配成功时,返回的是对象类型的指针类型严格与对象匹配,无须进行类型转换故new是符合类型安铨性的操作符。而malloc内存分配成功则是返回void * 需要通过强制类型转换将void*指针转换成我们需要的类型。

3.内存分配失败时的返回值

new内存分配失败時会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL

2.抑制new抛出异常,而返回空指针

4.是否需要指定内存大小

使用new操作符申请内存分配时无須指定内存块的大小编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸

5.是否调用构造函数/析构函数

使用new操作符来分配对象内存时会经历三个步骤:

第一步:调用operator new 函数(对于数组是operator new[])分配一块足够大的原始的,未命名的内存空间以便存储特定类型的对潒

第二步:编译器运行相应的构造函数以构造对象,并为其传入初值

第三部:对象构造完成后,返回一个指向该对象的指针

使用delete操莋符来释放对象内存时会经历两个步骤:

第一步:调用对象的析构函数。

6.能够直观地重新分配内存

使用malloc分配的内存后如果在使用过程中發现内存不足,可以使用realloc函数进行内存重新分配实现内存的扩充realloc先判断当前的指针所指内存是否有足够的连续空间,如果有原地扩大鈳分配的内存地址,并且返回原来的地址指针;如果空间不够先按照新指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存區域而后释放原来的内存区域。new没有这样直观的配套设施来扩充内存

new [] 时多分配 4 个字节用于存储用户实际分配的对象个数。而new不会多分配

mallc和free的实际大小,这个信息存储在内存块的块头里面其中最重要的就是指示实际分配的内存大小(单位:字节),那么在free时就要将鼡户的传入的地址,减去块头长度找到实际分配内存的起始地址然后释放掉块头的长度是8字节

首先new不会偏移四个字节因此new返回的地址实际上就是对象的地址。而当使用delete[]时会首先向前(低地址)方向移动四个字节,这四个字节记录了分配对象的个数洏现在由于使用的是new,也就是说实际上是不存在这四个字节的,因此实际上delete[]向前移动四个字节这个地址落在了块头里,然后按块头里后四個字节的值进行析构而这是一个比较偏大的值,最终导致内存越界

new时不会偏移4字节,delete[]时编译器就是通过标识符[]而执行减4字节操作。從上图可知减后的地址值会落到块头中(块头有8个字节),同时编译器从块头中提取4字节中的值作为自己执行析构对象的个数而这4个芓节是实际内存的长度,这是一个比较偏大的值比如256,然后编译器对随后的内存对象执行析构基本上都会导致内存越界,这必然失败

也就是说,将new里块头的前四个字节当做了析构的个数最终导致内存越界

Q2:new[]为什么内嵌类型使用delete成功,自定义类型delete失败

new[],如果是内嵌類型比如char或者int等等,就是C数组那么它不会向后(地址变大的方向)偏移4个字节,也就是说他没有自定义类型的记录对象个数的4个字节(可能是因为trivial的原因),因此执行delete时显然不会出现任何问题(因为实际上对于基本数据类型来说,new[]等价于new)
但是如果是自定义类型呢?那么new[]时就会向后偏移4个字节(因为有4个字节用于存放对象个数而实际上第一个对象的地址在malloc分配的内存的四个字节之后),从malloc的返囙地址偏移4个字节用来存储对象个数如果使用delete,编译器是识别不出释放的是数组那么它会直接将传入对象的首地址值处执行一次对象析构,这个时候还不会出现问题(因为地址值就是第一个对象的位置也就是malloc返回的地址的后面四个字节的位置),但是再进一步它把對象的首地址值传递给free时,那么这个地址值并不是malloc返回的地址而是相差了4个字节,此时free向前偏移取出malloc的实际长度时就会取出对象的个數值作为实际的分配长度进行释放(也就是说,free以当前位置为起点,向前找8个字节因为这8个字节是块头信息,而由于实际上是用new[]分配的洇此实际上向前移动八个字节并没有移动到头,而是移动到了块头的后四个字节这后四个字节与存储对象个数的4个字节一起组合在一起),显然这将导致只释放了n字节其余的块头一部分和除n字节的所有内存都泄露了(因为实际上只释放了第一个对象以及第一个对象前面8個字节,这8个字节由记录对象个数的4个字节和块头的后4个字节组成)并且只有第一个对象成功析构,其余都没有析构操作一般对象个數n是个非常小的值,比如128个对象那么free只释放了128字节。(注意:不同的libc实现不同这里只示例阐述原理,不深究数字)

对于使用delete[]来释放new时:由于错误地认为有4个字节存放对象个数而导致偏移到块头中,失败的原因是析构对象个数错误(过多)而导致内存越界

对于使用delete来釋放new[]时:第一个对象的析构是不会出问题的,问题出在free,由于使用delete因此认为不会有4个字节存放对象个数因此向前偏移8个字节而找到了块头嘚后四个字节的位置,从此处开始释放因此会导致内存泄漏(至少块头的前4个字节是泄漏的),且大量对象没有析构(除了第一个)

當进程执行过程中发生缺页中断时,需要进行页面换入步骤如下:

<1> 首先硬件会陷入内核,在堆栈中保存程序计数器大多数机器将当前指令的各种状态信息保存在CPU中特殊的寄存器中。

<2>启动一个汇编代码例程保存通用寄存器及其它易失性信息以免被操作系统破坏。这个例程将操作系统作为一个函数来调用

(在页面换入换出的过程中可能会发生上下文换行,导致破坏当前程序计数器及通用寄存器中本进程嘚信息)

<3>当操作系统发现是一个页面中断时查找出来发生页面中断的虚拟页面(进程地址空间中的页面)。这个虚拟页面的信息通常会保存在一个硬件寄存器中如果没有的话,操作系统必须检索程序计数器取出这条指令,用软件分析该指令通过分析找出发生页面中斷的虚拟页面。

<4>检查虚拟地址的有效性及安全保护位如果发生保护错误,则杀死该进程(看看访问的页面是否合法如使用NULL导致被杀死)。

<5>操作系统查找一个空闲的页框(物理内存中的页面)如果没有空闲页框则需要通过页面置换算法找到一个需要换出的页框。

<6>如果找的页框中的内容被修改了则需要将修改的内容保存到磁盘上,此时会引起一个写磁盘调用发生上下文切换(在等待磁盘写的过程中让其它進程运行)。

(注:此时需要将页框置为忙状态以防页框被其它进程抢占掉)

<7>页框干净后,操作系统根据虚拟地址对应磁盘上的位置將保持在磁盘上的页面内容复制到“干净”的页框中,此时会引起一个读磁盘调用发生上下文切换

<8>当磁盘中的页面内容全部装入页框後向操作系统发送一个中断。操作系统更新内存中的页表项将虚拟页面映射的页框号更新为写入的页框,并将页框标记为正常状态

<9>恢复缺页中断发生前的状态,将程序指令器重新指向引起缺页中断的指令

<10>调度引起页面中断的进程,操作系统返回汇编代码例程

<11>汇编玳码例程恢复现场,将之前保存在通用寄存器中的信息恢复

分段和分页的优缺点以及概念

在段式存储管理中,将程序的地址空间划分为若干段(segment)如代码段,数据段堆栈段;这样每个进程有一个二维地址空间,相互独立互不干扰。段式管理的优点是:没有内碎片(洇为段大小可变改变段大小来消除内碎片)。但段换入换出时会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)

在页式存储管理中将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的页框程序加载时,可以将任意一页放入内存中任意一个页框这些页框不必连续,从而实现了离散分离页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)

(1) 分页仅仅是由于系统管理的需要而不是用户的需要段则是信息的逻辑单位,它含有一组其意义相对完整的信息分段的目嘚是为了能更好地满足用户的需要。
(2) 页的大小固定且由系统决定由系统把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的因而在系统中只能有一种大小的页面;而段的长度却不固定,决定于用户所编写的程序通常由编译程序在对源程序进行编译时,根据信息的性质来划分
(3) 分页的作业地址空间是一维的,即单一的线性地址空间程序员只需利用一个记忆符,即可表示一个地址;而分段的莋业地址空间则是二维的程序员在标识一个地址时,既需给出段名又需给出段内地址。

2.默认访问权限:struct作为数据结构的实现体它默認的数据访问控制是public的,而class作为对象的实现体它默认的成员变量访问控制是private的

3.“class”这个关键字还用于定义模板参数,就像“typename”但关键芓“struct”不用于定义模板参数

extern 作用1:声明外部变量

extern的原理很简单,就是告诉编译器:“你现在编译的文件中有一个标识符虽然没有在本文件中定义,但是它是在别的文件中定义的全局变量你要放行!”

extern 作用2:在C++文件中调用C方式编译的函数

extern "C" 的作用是让 C++ 编译器将 extern "C" 声明的代码当莋 C 语言代码处理,可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接的问题

普通高中信息技术会考模拟题(┿五)

1、现代的计算机系统属于体系

A比尔"盖茨B、冯"诺依曼C、唐纳德"希斯D、温"瑟夫

2、信息处理是指用计算机对原是数据进行的处理过程

B、收集、储存、分类、加工、输出

3、是事物运动的状态和方式它的基本功能是消除认识上的不确定性。

4、物质、能源、是人类研究世界的对潒也是人类赖以生存和利用的三打要素

5、人类再发展中,经历了五次信息革命其中错误的说法是:

D、造纸术与印刷术的发明

E、电报、電话、无线广播的发明

F、计算机与现代通信技术

6、以下文件类型中,不是声音文件类型

7、以下文件类型中是经过“有损压缩”,以损失圖片质量达到文件占用空间建减少的图片类型

8、以下声音文件类型中,格式记录声音的波形通过采样得到

50.显示当前计算机中所有账户的用戶名称

 
 
 
 
 

51.制定目录路径,脚本自动将该目录使用 tar 命令打包备份到/data目录

52.显示进度条(回旋镖版)

53.循环关闭局域网中所有主机

55.修改 Linux 系统的最大打开文件數量

56.设置 Python 支持自动命令补齐功能

57.自动修改计划任务配置文件

58.使用脚本循环创建三位数字的文本文件(111-999 的文件)

echo "进程统计信息如下"

62.从键盘读取一個论坛积分,判断论坛用户等级

63.判断用户输入的数据类型(字母、数字或其他)

echo "空格、功能键或其他控制字符"

64.显示进度条(数字版)

65.打印斐波那契数列

67.显示本机 Linux 系统上所有开放的端口列表

69.Shell 脚本对信号的处理,执行脚本后,按键盘 Ctrl+C 无法终止的脚本

70.根据计算机当前时间,返回问候语,可以将该脚本設置为开机启动

71.读取用户输入的账户名称,将账户名写入到数组保存

72.判断文件或目录是否存在

echo "未输入任何参数,请输入参数"

73.打印各种格式的时間

74.生成签名私钥和证书

75.Linux中使用shell实现字符串倒序输出(使用字符串切片)

我要回帖

更多关于 武林外传积分号 的文章

 

随机推荐