面经

# css篇

# js、es6篇

```
1. 节流、防抖概念、应用场景、代码

节流、防抖: 防止高频触发事件造成性能浪费,增加浏览器负担,于是使用节流、防抖的方式减少触发次数

防抖:当时间持续触发,在一定时间之内(delay)没有触发后,事件处理函数执行一次

节流: 事件持续触发,事件处理函数在一定时间(delay)之内执行一次

应用场景: 

防抖

search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次

节流

鼠标不断点击触发,mousedown(单位时间内只触发一次)
监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断


        
实现代码: 见手撕代码2

```

```
2. js中defer、async区别

HTML文档解析过程:(无js文件)

解析html文档、生成DOM树 - 解析样式表,生成CSSOM - 根据CSSOM 和DOM 树结合生成render 树 -根据render树的内容计算元素节点在页面中的位置,渲染页面

普通js文件会阻塞文档解析过程:

解析HTML文件  - 加载样式文件和脚本文件 - 解析、执行脚本文件 - DOM树加载完毕(DOMContentLoaded) - 加载图片等外部文件 - 页面加载完毕(loaded)

此处,不同js文件对页面渲染造成不同效果

    1. 普通js文件: 遇到普通js文件,会阻塞页面解析加载,等到js文件解析执行完毕之后, 页面继续解析加载
    
    2. defer:js文件的加载与后续文档元素加载解析并发执行,js的执行会等待后续元素解析完毕,在DOMContentLoaded之前执行
    
    3. async:js文件的加载与后续文档元素加载并发执行,js不会等待页面解析,加载完成立即执行,执行顺序与DOMContentLoaded无关
    
注意事项:

    1. defer、async都是异步加载,defer原则上执行顺序按照在文档中位置,而async则是乱序,用于不需要以来DOM解析完成的情况
    
    2. 浏览器可以预测可能需要下载的资源,同时渲染不完整的DOM树和CSSOM,减少白屏事件,如果js文件放在头部, 会阻塞文档解析(为什么js文件放在</body>之前,而css文件放在header头部?)

```

```
3. commonjs模块 与 ES6模块

commonjs模块:

    1. 对于基本数据类型,加载是对变量的复制。会对模块缓存,使用缓存变量值,再另外一个模块中可以修改值(不影响原来模块中变量的值)
    
    2. 对于复杂数据类型,加载时属于浅拷贝,所以如果在另外一个模块中修改变量,会影响原来模块中应用类型的值
    
    3. require会在加载的时候立即执行
    
    4. 对于某个模块被多次加载,不会多次执行该模块,而是会取缓存值
    
    5. 循环引用中,可能会导致某模块代码只执行一部分,如果发现某模块被循环加载,只会输出已经执行的代码,未执行的不会输出
    
ES6: import、export(动态只读引用)

    1. 引用模块中不可以修改原来模块中变量
    
    2. 原模块更新时,import加载的之会相应变化
    
    3. 循环引用中,可以正常执行
```

```
4. ES6新增属性(解构赋值、let\const、拓展运算符、箭头函数、set\map、promise、async\await、generator、proxy、class类、string\numer\object\array等新增API)

promise、async\await、generator
```

# vue

```
1. vue之 MVVM 数据双向绑定原理以及实现

原理: mvvm数据双向绑定是通过数据劫持结合发布者-订阅者的模式, 利用object.defineProperty()的getter、setter访问器属性 ,当数据变动时通知订阅者,出发相应的回调、从而更新视图

步骤:

    1. 实现一个***Observer:数据***对数据对象的所有属性进行监听,当数据发生改变时,得到最新值并通知订阅者
    
    2. 实现一个订阅者Watcher:作为连接***和指令解析器的桥梁,可以接收到订阅的消息,执行绑定的回调函数, 更新视图
    
    3. 实现一个指令解析器Compile:对元素节点的每一个指令进行扫描与解析,根据指令模板替换数据并绑定对应的回调函数
    
    
实现代码:见手撕代码1

```

# react

# 项目

# http

```
1. http状态码

1xx: 接受请求、还需要进一步处理
2xx: 请求成功
3xx: 资源重定向
4xx: 客户端请求出错
5xx: 服务器端错误

100: 服务器接受到请求,还需进一步处理

200(OK):请求成功,服务器正常处理客户端请求并返回

204(No Content):客户端发送给服务器端的内容被正常处理,返回的响应报文中不含试题内容(没有资源可返回)

206 (Patial Content):客户端进行范围请求,服务器端正常处理请求,并返回了content-range指定的实体内容

301 (Moved Permanently): 永久重定向,之后请求使用新地址

302 (Found):临时重定向,这次请求使用新地址

303 (See Other):请求已经被处理,返回的不是响应文档,而是响应文档的URL,资源地址分配了新的URL,应该使用GET请求定向获取请求资源

304  (Not Modified):客户端发送附带请求(if-modify-since等),服务器端返回304,表示客户端已经拥有资源,资源未修改

307 (Temporary redirect)临时重定向,请求资源临时从不同的URI响应请求

400  (Bad Request):客户端语法错误

401 (Unauthorized): 未经许可。需要通过http认证

403 (Forbidden): 服务器拒绝请求,没有权限

404 (Not Found):请求资源不存在,或者服务器拒绝请求但不想给出原因的时候使用

500 (Inter Server Error):服务器执行请求时发生错误,也有可能是web应用存在bug或某些临时错误

503  (Server Unavailable):服务器处于超负载或者停机维护状态

```

```

2. 请求报文和响应报文

请求报文: 请求行(请求方法,请求地址,http版本协议)、请求首部(content-type)、空行、请求体

响应报文: 状态行(http版本协议、状态码、状态码描述)、响应首部、空行、响应体

(一)请求方法:get、post、head、put、delete、options、trace、connect

head: 只返回响应头不返回响应内容,如果只需要查看某页面状态时使用

delete: 删除某一个资源

put: 将某一个资源存放在指定的位置上。

options:获取当前URL所支持的请求方法(allow:get、put...)

trace:回显服务器收到的请求,通常用于测试或诊断

connect:将连接改为管道方式的代理服务器,通常用于ssl加密服务器的链接或者非加密http的代理服务器通信

get、post请求区别

1. get请求重点在于向服务器请求数据;post请求侧重于向服务器发送数据

2. get请求的请求参数通过url地址拼接的方式连接在请求地址上;post请求的请求参数通过请求主体发送给服务器

3. get请求只支持ascll编码,post请求可支持任何编码

4. get请求相对post请求不那么安全

5. get请求数据传输量少于post请求

6. GET在浏览器回退时是无害的,而POST会再次提交请求

7. GET请求会被浏览器主动cache,而POST不会,除非手动设置(cache-control)

8. get请求产生一个数据包,post请求产生两次数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);

而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

post、put请求区别

put请求: 对于两次相同的请求,put请求后一次请求会覆盖前一次(put请求适合用于更改资源)

post请求: 对于两次相同的请求,post后一次请求不会覆盖前一次请求(post请求适合用于增加资源)

在网络环境较差的情况下,发送两次数据包在验证数据完整性上有非常大的优点,fir fox只发送一次包

(二)content-type

application/www-x-form-urlencoded 表单提交 key=value

mutipart/form-data  文件上传、发送二进制数据

application/json  序列化JSON字符串

text/xml

```

```

3. http 强缓存、协商缓存

```
![image](https://upload-images.jianshu.io/upload_images/1705225-9173e6f70849ca81.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/556/format/webp)
```

HTTP缓存机制

(1)缓存规则解析

浏览器中存在一个缓存数据库,用于存储缓存信息。当客户端第一次请求数据时,由于缓存数据库中没有该数据,则需要向服务器发送请求,将返回的数据存入缓存系统

(2)分类:强制缓存和对比缓存(协商缓存)

  强制缓存:
    a.命中缓存: 请求数据, 存在缓存数据,且未失效,返回缓存数据
    b.未命中缓存: 请求数据, 缓存数据失效, 请求服务器, 返回数据, 将数据存放在缓存系统中
  对比缓存:
    a.命中缓存:获取缓存数据标识,返回缓存数据标识, 请求服务器验证缓存标识对应的数据是否失效, 通知客户端数据未失效, 客户端从缓存中获取数据
    b.未命中缓存,获取缓存数据标识,返回缓存数据标识, 请求服务器验证缓存标识对应的数据是否失效, 返回最新数据和缓存规则, 客户端从缓存中获取数据
            
(3)优先级:强制缓存高于对比缓存,强制缓存生效则不再执行对比缓存

(4)强制缓存是否失效?(expires/cache-control)

     浏览器请求数据时,会将数据和缓存规则一并返回,缓存信息包含在响应header中

     强制缓存中通过Expires/Cache-Control来表明失效规则

     a.Expires值为服务器返回的到期时间,当请求时间小于到期时间,则直接使用缓存数据
     b.Cache-Control:由于Expires存在服务器时间和浏览器时间的误差,所以使用Cache-Control代替

      常见取值:
            private: 客户端可以缓存; public:客户端和代理服务器可以缓存
            max-age = xxx 缓存内容在xxx秒后失效
            no-chache:需要使用对比缓存
            no-store: 所有内容都不会被缓存(不会使用强制缓存和对比缓存)
            
(5)对比缓存是否可以使用缓存数据(通过缓存标识来判断)
两种标识传递
    a.last-modified/if-modified-since:
    
       last-modified:第一次请求时,请求资源最后修改的时间(服务器端最后修改)
       if-modified-since:再次请求是,通知服务器上次请求时间,服务器返回最后修改的时间(客服端最后修改)
                    服务器通过比较最后修改时间和if-modified-since的值,
                    如果最后修改的时间大于if-modified-since,则需要返回请求资源内容,状态吗200
                    如果最后修改的时间小于if-modified-since,则返回304,使用缓存数据
                    
    b.etag/if-none-match(优先级高于last-modified/if-modified-since)
    
        etag: 第一次请求时,返回数据唯一标志
        if-none-match: 再次请求时,通知服务器上一次请求时,返回的资源标  服务器比较当前资源标志和if-none-match的值,如果相等,则返回304;否则200
```
[缓存机制博客参考](https://www.cnblogs.com/chenqf/p/6386163.html/)


```
(TCP、UDP)

1. 端口号

在 tcp/ip 协议中,通过源IP地址、目标IP地址、协议号、源端口号、目标端口号确认一个通信

端口号唯一标志一个主机上的不同应用程序之间的通信

2. TCP/UDP区别

a.从各自特点来看

(1)TCP面向连接,UDP面向无连接

TCP通信是建立在连接上,UDP通信不需要建立连接

(2)TCP可靠,UDP不可靠

TCP通过连接管理、超时重传、确认机制、流量控制、拥塞阻止保证可靠性, 而UDP不存在这些控制,且如果网络发生错误,不会发送错误信息

(3)TCP有发送数据缓存区,UDP只有接收数据缓存区

TCP存在发送数据缓存区,保证数据重传正常进行,UDP不存在数据重传,接收数据的缓存区(接受的数据次序与发送数据次序不能保证一致)一旦满了,就会丢失数据。

(4)TCP一对一连接,UDP支持一对一、一对多、多对一连接

(5)TCP面向字节流、UDP面向数据流

b.报文头部

(1)TCP默认20个字节、UDP默认8个字节,TCP比UDP更浪费资源

(2)UDP报文头部包括源端口号、目标端口号、16位校验和、16为总长度; TCP报文头部除了源端口号、目标端口号、16位校验和 还包括6位标志位,序号,确认序号,窗口大小,等确保可靠性
(3)UDP报文头部16位总长度确认UDP报文长度;TCP虽然有4位首部长度,只能确认TCP报头长度,不能确认TCP报文长度,所以TCP存在粘包问题

c. 编程

服务器端:

都需要创建套接字socket
bind将IP和端口号绑定到socket上

对于UDP,此时可以开始通信

对于TCP, 需要使用listen监听客户端的请求,之后一直使用accept阻塞等待客户端连接,直到客户端连接,进行数据通信

客户端:

创建套接字socket

对于UDP,此时客户端可以发送数据请求

对于TCP,需要与TCP服务器建立连接,确认建立连接之后,发送数据

3.TCP的粘包问题

粘包:由于TCP报文没有指定长度或明确界限,且面向字节流,对于客户端不知道如何分割数据包,从而导致读取数据包出错

解决方法:

(1) 指定数据包长度
(2) 明确有效数据长度
(3) 使用指定分隔符

4. TCP可靠性保证

(1)应答ACK机制

TCP协议中,接收方接收到数据后,会回复一个ACK数据包,表示已经确认收到ACK确认号前的所有数据。也就是告诉发送方,我已经收到了哪些数据,下一次从哪里发送

(2)超时重传

当发送方发送给接收方的数据,接收方没有收到时,就无法发送ACK包,在一定时间后接收方仍旧没有收到ACK,就会重新发送该数据段

可能是ack丢包,这时候发送方会发送接收方已经接收到的数据,接收方可以通过序号轻松的将重复的数据去掉。

(3)滑动窗口

选择一次发送多组数据

发送前四个段时,不需要等待可以同时发送,当收到第一个ACK时,滑动窗口向后滑动,第五段的数据才可以进行发送。操作系统为了维护这个滑动窗口,开辟了发送缓冲区,来记录有哪些数据没有收到应答;只有收到应答的数据才可以从缓冲区删除。滑动窗口越大,网络吞吐率越高。

(4)流量控制

接收端处理数据的能力有限,如果发送端发送数据太快,导致接收端缓冲区满了,这时候如果发送方继续发送数据,就有可能造成丢包

TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制叫做流量控制。

(5)慢启动和拥塞控制
发送窗口是一个动态变化大小的窗口,当网络状况良好的时候,拥塞窗口增加,发送窗口增加,由于接收方处理能力有限,增加到一定程度就不再增加

慢启动,发送数据包之前先探测一下网络状况,如果状况良好,发送方每次发送都能接受正确的接受确认的报文,则增加拥塞窗口的大小。

(6)延迟应答
(7)捎带应答
```


```
TCP详细报文头部信息

源端口号,目的端口号:表示数据从哪来,到哪去
32位序号和确认序号
4位首部长度:表示TCP报头的长度(有多少个4个字节);TCP头部的最大长度是60
保留的6位是标志位:
URG:紧急指针是否有效

ACK:确认号是否有效

PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走

RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段

SYN:请求建立连接;我们把携带SYN标识的称为同步报文段

FIN:通知对方,本端要关闭了,我们把携带FIN标识的称为结束报文段

窗口大小:表示了发送方接下来要发送的数据的多少(根据接收方缓冲区的大小决定)
校验和:发送端填充,CRC校验(循环冗余校验);接收端校验若不通过,说明数据有问题
紧急指针

```





# 手撕代码


```
1. 实现vue--mvvm数据双向绑定

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>数据双向绑定</title>
</head>
<body>
    <div id="app">
        <form>
          <input type="text"  v-model="number">
          <button type="button" v-click="increment">增加</button>
        </form>
        <h3 v-bind="number"></h3>
        <p v-bind="name"></p>
      </div>

      <script>
          window.onload = function(){
            var app = new myVue({
              el: '#app',
              data: {
                  number: 0
              },
              methods: {
                  increment: function(){
                      this.number++;
                  }
              }
            })
          }

          function myVue(options){
              this._init(options);
          }

          myVue.prototype._init = function (options) {
            this.$options = options;
            this.$el = document.querySelector(options.el)
            this.$data = options.data;
            this.$methods = options.methods

            this._binding = {}      //_binding中保存着model与view的映射关系,即watcher的实例。当model变化的时候,触发指令类更新,保证视图实时更新
            this._obverse(this.$data);  //数据***
            this._compile(this.$el)     //指令解析器

            console.log(this._binding)
          }
          
          // 数据***
          myVue.prototype._obverse = function (obj) {
            var value;
            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
                    value = obj[key];
                    console.log(key, value)
                    if (typeof value === 'object') {
                        this._obverse(value);
                    }
                    this._binding[key] = {                                                                                                                                                          
                         _directives: []
                    };      // 用于保存watcher实例
                    
                    var binding = this._binding[key];
                    Object.defineProperty(this.$data, key, {
                        enumerable: true,
                        configurable: true,
                        get: function () {
                            console.log(`获取${value}`);
                            return value;
                        },
                        set: function (newVal) {
                            console.log(`更新${newVal}`);
                            if (value !== newVal) {
                            value = newVal;
                            console.log(binding)
                            binding._directives.forEach(function (item) {
                                console.log(item)
                                item.update();
                            })
                            }
                        }
                    })
                }
            }
           }
          // 数据订阅者--绑定更新函数、实现对Dom更新视图
          function Watcher(name, el, vm, exp, attr){
            this.name = name;   //指令名称:text、input
            this.el = el;       //指令对应DOM节点
            this.vm = vm;       //指令所属myVue实例
            this.exp = exp;     // 指令对应的值, number
            this.attr = attr;   // 绑定的属性值, innerhtml

            this.update()
          }
          Watcher.prototype.update = function(){
                this.el[this.attr] = this.vm.$data[this.exp]    //h3.innerHTML = this.data.number
          }
          // 指令解析器
          myVue.prototype._compile = function(root){
              var _this = this;
              var nodes = root.children;

              for(var i = 0;i < nodes.length; i++){
                  var node = nodes[i]
                  if(node.children.length){
                      this._compile(node)
                  }
                  if(node.hasAttribute('v-click')) {
                      node.onclick = (function(){
                        var exp = nodes[i].getAttribute('v-click')
                        return _this.$methods[exp].bind(_this.$data)
                      })()
                  }

                  if(node.hasAttribute('v-model') && (node.tagName) == 'INPUT' || (node.tagName) == 'TEXTAREA'){
                      node.addEventListener('input', (function(key){
                          var exp = node.getAttribute('v-model');
                            // 数据更新时 视图同步更新
                          _this._binding[exp]._directives.push(new Watcher(
                              'input',
                              node,
                              _this,
                              exp,
                              'value'
                          ))
                          
                          // view更新  视图更新
                          return function() {
                              _this.$data[exp] = nodes[key].value;
                          }
                      })(i))
                  }
                  
                  if (node.hasAttribute('v-bind')) { // 如果有v-bind属性,我们只要使node的值及时更新为data中number的值即可
                    var exp = node.getAttribute('v-bind');
                    _this._binding[exp]._directives.push(new Watcher(
                    'text',
                    node,
                    _this,
                    exp,
                    'innerHTML'
                    ))
                   }
                }
          }
      </script>
</body>
</html>
```

```
2. 节流、防抖

// 防抖
function debounce(fn, delay){
    var timer = null;
    return function(){
        if(timer) timer = null;
        timer = setTimeout(fn, delay)
    }
}

//节流
function throttle(fn, delay){
// 时间戳
    var startTime = Date.now();
    return function(){
        var curTime = Date.now();
        var args = arguments;
        var context = this;
        if(curTime - startTime > delay){
            fn.apply(context, args);
            startTime = Date.now();
        }
    }
}
function throttle(fn, delay){
//定时器
    var timer = null;
    return function(){
        var args = arguments;
        var context = this;
        if(!timer){
            timer = setTimeout(function(){
                console.log(context, args)
                fn.apply(context, args)
                timer = null;
            }, delay)
        }
    }
}

function throttle(fn, delay){
// 时间戳 + 定时器
    var timer = null;
    var startTime = Date.now();
    return function(){
        var args = arguments;
        var context = this;
        var now = Date.now();
        var remain = delay - (startTime - now);
        clearTimeout(timer)
        if(remain <= 0){
            fn.apply(context, args)
        }else{
            setTimeout(function(){
                fn.apply(context, args)
                timer = null;
            },remain)
        }
    }
}
function handle(){
    console.log(Date.now())
}

window.addEventListener('scroll', throttle(handle, 1000))
```

```
3. 实现一个EventEmitter

class EventEmitter{
    constructor(){
        this.handles = {}
    }
    on(eventName, callback){
        if(!this.handles){
            this.handles = {}
        }
        if(!this.handles[eventName]){
            this.handles[eventName] = []
        }
        this.handles[eventName].push(callback)
    }
    emit(eventName, args){
        if(this.handles[eventName]){
            for(var i = 0;i < this.handles[eventName].length;i++){
                this.handles[eventName][i](args)
            }
        }
    }
}

var emitter = new EventEmitter();
var data = 'hello'
emitter.on('msg', function(data){
    console.log(data)
})
emitter.emit('msg', data)
```

```
4. 原生实现promise简版

function Promise(fn){
    var value = null, succallbacks = [], errcallbacks = []
    function resolve(value){    //把值传递给成功回调函数
        process.nextTick(function(){
            succallbacks.forEach(item => {
                item(value)
            })
        }, 0)
    }
    function reject(value){     //值传递给失败回调函数
        process.nextTick(function(){
            errcallbacks.forEach(item => {
                item(value)
            })
        }, 0)
    }
    this.then = function(sucfn, errfn){
        succallbacks.push(sucfn)
        errcallbacks.push(errfn)
        return this;
    }

    fn(resolve, reject)
}
```


# 算法

# 数据库篇

```
1. mysql之索引和事务

一、索引

索引: 为了方便数据库查询,代价增加了i/o操作

分类: 主键索引、唯一索引、普通索引、全文索引

操作: 

创建索引: 

主键索引(primary key): 

          create table user1(
            id int primary key,
            name varchar(30)
           )
           
           create table user2(
            id int,
            name varchar(30),
            primary key(id)
           )
           
           create table user3(
            id int,
            name varchar(30)
           )
           
           alert table user3 add primary key(id)
           
唯一索引(unique)

            create table user1(
                id int unique,
                name varchar(30)
            )
            create table user2(
                id int not null,
                name varchar(30),
                unique(id)
            )
            create table user3(
                id int,
                name varchar(30)
            )
            
            alert table user3 add unique(id)
普通索引(index)
            create table user1(
                id int,
                name varchar(30),
                index(id)
            )
            
            create table user2(
                id int,
                name varchar(30)
            )
            alert table user2 add index(id)
            
删除索引drop

主键索引删除:alert table table_name drop primary

其他索引: alert table table_name drop index index_name
           drop index index_name on table_name
           
创建索引原则:
1. 频繁作为查询条件,不能频繁更新,不能唯一性太差,会出现在where字句中的字段

二、 事务

事务:包括一组数据库DML语句(insert、delete、update、select),是不可分割的工作逻辑单元,会将所有的语句一起向系统提交或者失败撤销,即要么都执行要么都不执行。

特点:原子性、一致性、隔离性、持久性

原子性: 事务中的元素必须作为一个整体提交或者撤销,如果一个元素失败,这个事务提交失败

一致性: 事务必须保持一致性,如果正在执行的事务导致数据不一致,执行完毕之后任然保持一致性

隔离性: 事务是独立的,不应该以任何方式依赖或影响其他事务

持久性: 一旦事务提交,会永久保存在数据库中

常见操作:

start transition   开启事务
commit             提交事务
savepoint xxx      可以回退到指定事务
rollback           事务回滚
```

```
2. 死锁

(1)概念: 由于进程之间争夺资源,导致进程无法向前推进

(2)产生原因:

    1. 资源分类:
    
        可剥夺资源: 某进程获得之后,可被其他进程剥夺,如: CPU、主存
        
        不可剥夺资源: 某进程获得之后,不可被其他进程剥夺
        
    2. 进程间推进算法
    
    若P1保持资源R1,请求资源R2,而P2进程保持资源R2,请求资源R1,此时系统处于不安全状态,导致发生死锁
    
(3)死锁产生的四个必要条件

    1. 互斥条件:资源不可同时被两个进程使用
    
    2. 请求与保持条件:当进程由于请求资源造成阻塞时,对持有的资源保持不放
    
    3. 不可剥夺条件:进程对已经请求得到而未使用完的资源,不可剥夺,自能使用结束自己释放
    
    4. 环路等待条件: 产生死锁时,资源-进程存在一个环形闭合回路
    
(4)预防死锁:

    1. 一次性分配所有请求资源,没有再有后续请求(破坏请求条件)
    
    2. 当有一个资源得不到分配时,不给这个进程分配其他资源(破坏保持条件)
    
    3. 破坏不可剥夺:当进程获得某部分资源,而得不到其他资源的时候,释放已经占有资源
    
    4. 有序进行资源请求

    以确定顺序获得资源、超时释放
    
(5)避免死锁:(银行家算法)

    进程请求资源之前,系统判断分配资源是否会进入不安全状态,如果不安全,则系统阻止分配资源给该进程
    
(6)检测死锁

    1. 为进程和资源指定唯一编号
    
    2. 建立进程表和资源表
    
(7)解除死锁

    1. 剥夺资源
    
    2. 撤销进程
```

全部评论

相关推荐

点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务