操作系统

操作系统 1 基础概念 1.1 操作系统功能 **进程和线程管理:**进程的创建、撤销、阻塞、唤醒,进程间的通信。 **存储管理:**内存的分配和管理、外存(磁盘)的分配和管理。 **文件管理:**文件的读写、创建及删除。 **设备管理:**完成设备的请求或释放,以及设备的启动等功能。 **网络管理:**操作系统负责管理计算机网络的使用,管理网络的配置、连接、通信、安全等。 **安全管理:**用户身份认证,访问控制、文件加密等。 1.2 用户态和内核态 用户态(User Mode) : 用户态运行的进程可以直接读取用户程序的数据,拥有较低的权限。当应用程序需要执行某些需要特殊权限的操作,例如读写磁盘、网络通信等,就需要向操作系统发起系统调用请求,进入内核态。 内核态(Kernel Mode):内核态运行的进程几乎可以访问计算机的任何资源包括系统的内存空间、设备、驱动程序等,不受限制,拥有非常高的权限。当操作系统接收到进程的系统调用请求时,就会从用户态切换到内核态,执行相应的系统调用,并将结果返回给进程,最后再从内核态切换回用户态。 内核态相比用户态拥有更高的特权级别,因此能够执行更底层、更敏感的操作。不过,由于进入内核态需要付出较高的开销(需要进行一系列的上下文切换和权限检查),应该尽量减少进入内核态的次数,以提高系统的性能和稳定性。 用户态和内核态的切换: 系统调用:用户态进程主动切换 中断:当外围设备完成用户请求的操作后,会向 CPU 发出相应的中断信号,这时 CPU 会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。 异常:当 CPU 在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。 在系统的处理上,中断和异常类似,都是通过中断向量表来找到相应的处理程序进行处理。区别在于,中断来自处理器外部,不是由任何一条专门的指令造成,而异常是执行当前指令的结果。 1.3 系统调用 我们运行的用户程序中,凡是与系统态级别的资源有关的操作(如文件管理、进程控制、内存管理等),都必须通过系统调用方式向操作系统提出服务请求,并由操作系统代为完成。 系统调用和普通库函数调用非常相似,只是系统调用由操作系统内核提供,运行于内核态,而普通的库函数调用由函数库或用户自己提供,运行于用户态。 系统调用过程: 用户态发起系统调用,用户态权限不足,中断执行(Trap) CPU执行的程序终端,跳转到终端处理程序,内核程序开始执行。 内核处理后,主动出发Trap,再次发生中断,切换回用户态工作。 2 进程和线程 2.1 进程 进程(Process) 是指计算机中正在运行的一个程序实例。资源分配的基本单位。 PCB是什么? PCB(Process Control Block) 即进程控制块,是操作系统中用来管理和跟踪进程的数据结构,每个进程都对应着一个独立的 PCB。你可以将 PCB 视为进程的大脑。 当操作系统创建一个新进程时,会为该进程分配一个唯一的进程 ID,并且为该进程创建一个对应的进程控制块。当进程执行时,PCB 中的信息会不断变化,操作系统会根据这些信息来管理和调度进程。 PCB 主要包含下面几部分的内容: 进程的描述信息,包括进程的名称、标识符等等; 进程的调度信息,包括进程阻塞原因、进程状态(就绪、运行、阻塞等)、进程优先级(标识进程的重要程度)等等; 进程对资源的需求情况,包括 CPU 时间、内存空间、I/O 设备等等。 进程打开的文件信息,包括文件描述符、文件类型、打开模式等等。 处理机的状态信息(由处理机的各种寄存器中的内容组成的),包括通用寄存器、指令计数器、程序状态字 PSW、用户栈指针。 进程有哪些状态?(生命周期) ...

September 26, 2024 · 3 min · 635 words · RLTEA

操作系统-面试重点问题

操作系统-面试重点问题

September 26, 2024 · 1 min · word · RLTEA

数据结构

数据结构 1 线性数据结构 1.1 数组 1.2 链表 1.3 栈 1.4 队列 2 图 2.1 基本概念 2.2 图的存储 2.3 图的搜索 2.3.1 DFS public int[] findOrder(int numCourses, int[][] prerequisites) { // adjacency list Set<Integer>[] graph = new Set[numCourses]; for (int[] e : prerequisites) { // e[0] depends on e[1] // e[1] --> e[0] if (graph[e[1]] == null) { graph[e[1]] = new HashSet<>(); } graph[e[1]].add(e[0]); } List<Integer> list = new ArrayList<>(numCourses); boolean[] globalVisited = new boolean[numCourses]; boolean[] localVisited = new boolean[numCourses]; // to check cycle for (int i = 0; i < numCourses; ++i) { if (!dfs(graph, i, globalVisited, localVisited, list)) { return new int[0]; } } // copy and reverse int[] result = new int[numCourses]; for (int i = 0; i < numCourses; ++i) { result[i] = list.get(numCourses - i - 1); } return result; } // return: can finish public boolean dfs(Set<Integer>[] graph, int node, boolean[] globalVisited, boolean[] localVisited, List<Integer> list) { if (localVisited[node]) return false; if (globalVisited[node]) return true; localVisited[node] = true; globalVisited[node] = true; Set<Integer> next = graph[node]; if (next != null) { for (Integer n : next) { if (!dfs(graph, n, globalVisited, localVisited, list)) { // return false and exit, no need to reset localVisited return false; } } } localVisited[node] = false; // reset list.add(node); return true; } 2.4 图的路径 2.4.1 弗洛伊德 class Solution { public int networkDelayTime(int[][] times, int N, int K) { // w[i][j]: time from [i] to [j], Integer.MAX_VALUE: inf int[][] w = new int[N+1][N+1]; for (int i = 1; i <= N; ++i) { Arrays.fill(w[i], Integer.MAX_VALUE); w[i][i] = 0; } for (int[] e : times) { int u = e[0], v = e[1], t = e[2]; w[u][v] = t; } for (int k = 1; k <= N; ++k) { for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { int sum; if (w[i][k] == Integer.MAX_VALUE w[k][j] == Integer.MAX_VALUE) { sum = Integer.MAX_VALUE; } else { sum = w[i][k] + w[k][j]; } w[i][j] = Math.min(w[i][j], sum); } } } int max = -1; for (int j = 1; j <= N; ++j) { if (w[K][j] == Integer.MAX_VALUE) return -1; max = Math.max(max, w[K][j]); } return max; } } 2.4.2 Dijkstra class Solution { public int networkDelayTime(int[][] times, int N, int K) { // graph[i]: List<int[]>, [to node, w] List<int[]>[] graph = new List[N+1]; for (int i = 1; i <= N; ++i) { graph[i] = new LinkedList<>(); } for (int[] e : times) { int from = e[0], to = e[1], w = e[2]; graph[from].add(new int[]{to, w}); } // [distance, node] PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[0] - b[0]); // node --> min distance HashMap<Integer, Integer> dist = new HashMap<>(); heap.offer(new int[]{0, K}); while (heap.size() > 0) { int[] n = heap.poll(); int distance = n[0]; int node = n[1]; if (dist.containsKey(node)) continue; // already determined dist.put(node, distance); // node determined for (int[] g : graph[node]) { int nextNode = g[0]; int w = g[1]; // K --> ... --> node --> nextNode if (dist.containsKey(nextNode)) continue; // alreay determined heap.offer(new int[]{distance + w, nextNode}); } } if (dist.size() != N) return -1; int max = -1; for (int d : dist.values()) { max = Math.max(max, d); } return max; } } 2.5 图的出入度问题 class Solution { public int[] findOrder(int numCourses, int[][] prerequisites) { Map<Integer, List<Integer>> graph = new HashMap<>(); int[] indegree = new int[numCourses]; for (int[] e : prerequisites) { // e[0] depends on e[1] // e[1] --> e[0] int pre = e[1], cur = e[0]; List<Integer> list = graph.get(pre); if (list == null) { list = new LinkedList<>(); graph.put(pre, list); } list.add(cur); indegree[cur]++; } Queue<Integer> queue = new LinkedList<>(); for (int i = 0; i < numCourses; ++i) { if (indegree[i] == 0) { queue.add(i); } } int[] result = new int[numCourses]; int size = 0; while (queue.size() > 0) { int node = queue.poll(); result[size++] = node; List<Integer> next = graph.get(node); if (next != null) { for (int n : next) { indegree[n]--; if (indegree[n] == 0) { queue.offer(n); } } } } if (size != numCourses) return new int[0]; return result; } } 2.6 最小生成树 2.6.1 Kruskal class Solution { public int minimumCost(int N, int[][] connections) { // sort connections by cost from small to large Arrays.sort(connections, (a,b) -> a[2]-b[2]); int[] parent = new int[N+1]; for (int i = 1; i <= N; ++i) { parent[i] = i; } int cost = 0; for (int[] edge : connections) { if (union(edge[0], edge[1], parent)) { cost += edge[2]; } } // check if all the roots are the same int p = -1; for (int i = 1; i <= N; ++i) { int root = findRoot(i, parent); if (p == -1) { p = root; } else if (p != root) { return -1; } } return cost; } public int findRoot(int x, int[] parent) { while (x != parent[x]) { parent[x] = parent[parent[x]]; x = parent[x]; } return x; } public boolean union(int a, int b, int[] parent) { a = findRoot(a, parent); b = findRoot(b, parent); if (a == b) return false; parent[a] = b; return true; } } 2.6.2 Prim class Solution { public int minimumCost(int N, int[][] connections) { int INF = Integer.MAX_VALUE; // graph[i][j]: // INF: not reachable // x: distance int[][] graph = new int[N+1][N+1]; for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { if (i == j) graph[i][j] = 0; else graph[i][j] = INF; } } for (int[] edge : connections) { int u = edge[0], v = edge[1], w = edge[2]; graph[u][v] = graph[v][u] = w; } // dist[i] // d: current min distance from one of added nodes // INF: distance is inf, not reachable int[] dist = new int[N+1]; Arrays.fill(dist, INF); // added nodes boolean[] added = new boolean[N+1]; // set node [1] as candidates dist[1] = 0; int cost = 0; for (int k = 0; k < N; ++k) { // N nodes to add // find node with min distance int min = INF; int node = -1; for (int i = 1; i <= N; ++i) { if (!added[i] && dist[i] < min) { min = dist[i]; node = i; } } // no reachable node found if (node == -1) { return -1; } // add [node] cost += dist[node]; added[node] = true; // update dist[i] with distance from [node] to [i] for (int i = 1; i <= N; ++i) { if (added[i]) continue; if (graph[node][i] == INF) continue; dist[i] = Math.min(dist[i], graph[node][i]); } } return cost; } } 3 堆 3.1 概念 3.2 分类 3.3 存储 3.4 操作 3.5 排序 4 树 4.1 分类 4.2 存储 4.3 遍历 5 红黑树 5.1 概念与特点 红黑树是一种自平衡二叉查找树。JDK中,TreeMap、TreeSet以及HashMap都使用了红黑树。 ...

September 26, 2024 · 7 min · 1372 words · RLTEA

结构性模式

结构性模式 通过类和接口间的继承和引用关系船舰结构复杂的对象。 1 适配器模式 当需要将两个不同接口的类进行通信时,在不修改这两个类的前提下,我们可以用中间件完成衔接过程。这个中间件就是适配器,适配器模式就是将一个类的接口,转换为客户期望的另一个接口,让原本不兼容的接口完成无缝对接。 类适配器 通过类的继承实现适配,继承Target的接口,继承Adaptee的实现 对象适配器 通过类对象的组合实现适配 target:定义Client真正需要的接口。 Adaptee:其中定义了一个已经存在的接口,也就是我们需要进行适配的接口。 Adapter:对Adaptee和Target的接口进行适配,保证对target中接口的调用可以间接转换为对Adaptee中接口的调用。 优点: 提高了类的复用 组合若干关联对象对外提供统一服务接口 扩展性、灵活性号 缺点: 过多使用适配器模式容易导致代码功能和逻辑意义混淆。 部分语言对继承的限制,可能至多只能适配一个适配者类么日期目标类必须是抽象类。 2 桥接模式 3 组合模式 4 装饰模式 5 外观模式 6 享元模式 7 代理模式 代理模式本质是一个中间件,主要目的时解耦合服务提供者和使用者。 使用者通过代理间接访问服务提供者,便于后者的封装和控制。 RealSubject:真正的目标对象 Proxy:目标对象的代理,负责控制和管理目标对象,并间接传递外部对目标对象的访问 Remote Proxy:对本地的请求以及参数进行序列化,向远程对象发送请求,并对响应结果进行反序列化,将最终结果反馈给调用者。 Virtual Proxy:当目标对象创建开销比较大时,可以使用延迟或者异步的方式创建目标对象 Protection Proxy:细化对目标对象访问权限的控制 静态代理和动态代理的区别 动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要整堆每个目标类都创建一个代理类。 静态代理中,一旦新增方法,目标对象和代理对象都要修改。 JVM中,静态代理在编译时就将接口、实现类、代理类编译成class文件,动态代理是在运行时动态生成字节码文件,加载到JVM中的。

September 26, 2024 · 1 min · 45 words · RLTEA

行为型模式

行为型模式 通过类之间不同的通信方式实现不同行为。 1 访问者模式 2 模板模式 3 策略模式 属于对象的行为模式,针对一组算法,将每一个算法封装到具有共同接口的独立类中,使得他们可以相互替换。 4 状态模式 5 观察者模式 Subject:抽象被观察对象,仅提供注册和删除观察者对象的接口声明。 ConcreteSubject:具体被观察对象,该对象中收集了所有需要被通知的观察者,可以动态增删集合中的观察者,当状态发生变化时,会通知所有观察者对象。 Observer:抽象观察者,为所有观察者定义获得通知的同一接口。 ConcreteObserver:观察者对象,关注对象为Subject,能接受Subject变化是发出的通知并更新自身状态 优点: 被观察者和观察者之间时抽象耦合的 耦合度较低,两者之间关联仅在于消息通知 被观察者者无需关心他的观察者 支持广播通信 缺点: 观察者只知道被观察对象发生了变化,不知道过程和原因 观察者同时可能是被观察者,消息链路可能过长 如果观察者和被观察者之间产生循环依赖,会导致无限循环 6 备忘录模式 7 中介者模式 8 迭代器模式 9 解释器模式 10 装饰器模式 对现有类对象进行包装,在不改变类对象和定义情况下,添加额外功能。 是一种对象结构型模式。 Component:对象的接口类,定义装饰对象和被装饰对象的共同接口 ConcreteComponent:被装饰对象的定义 Decorator:装饰对象的抽象类,持有一个具体被修饰的对象,并实现接口类继承的公共接口 ConcreteDecorator:具体的装饰器,负责王被装饰对象添加额外功能。 final修饰的类无法使用继承来拓展对象行为,此时可以使用装饰模式进行拓展。 11 命令模式 12 责任链模式 一个请求沿着一条链传递,直到该链上某个处理者处理它为止。 当程序需要使用不同方法处理不同种类请求时,而且请求类型和顺序预先未知时。使用责任链模式,收到请求后,按顺序询问每个处理者是否能够处理

September 26, 2024 · 1 min · 49 words · RLTEA

计算机网络

计算机网络 1 分层模型 OSI七层模型: 口诀:物联网书会使用 优点:概念结构清楚,理论完整 缺点:复杂不实用、某些功能在多个层中重复出现。 TCP/IP四层模型: 为什么要分层? 使得各层之间独立。 提高灵活性和可替换性(高内聚低耦合)。 大问题化小,复杂问题分解。 2 常见网络协议 应用层: HTTP SMTP POP3/IMAP FTP Telnet SSH RTP DNS 传输层: TCP UDP 网络层: IP ARP ICMP NAT OSFP RIP BGP 3 HTTP 3.1 从输入URL到页面展示发生了什么? 过程: 用户输入URL。 浏览器查找域名IP地址(通过DNS:浏览器缓存、路由器缓存、DNS缓存)。 浏览器根据IP地址和端口号,向目标服务器发起TCP连接请求。 浏览器与服务器建立TCP连接,并发送HTTP请求报文。 服务器收到报文进行处理请求,并返回HTTP响应报文给浏览器。 浏览器收到HTTP响应报文后,解析响应体中的内容,并进行网页渲染,同时根据HTML中其他资源URL再次发起HTTP请求,直到网页完全加载显示。 浏览器在不需要和服务器通信时,可主动关闭TCP连接,或者等待服务器关闭请求。 使用到的协议:DNS、TCP、IP、OPSF、ARP、HTTP 3.2 HTTP和HTTPS的区别 URL前缀不同(http和https) 端口号不同(80和443) 安全性,HTTPS大于HTTP 资源消耗:HTTP优于HTTPS SEO搜索引擎优化:优先显示HTTPS网页 ::HTTPS中的S如何实现?:: 3.3 HTTP/1.0和HTTP/1.1区别 1.1实现了长连接 1.1加入了大量状态码 1.1有更多的缓存控制机制 1.1支持断点续传 3.4 HTTP/1.1和HTTP/2.0区别 2.0实现了多路复用 2.0使用二进制帧传输(1.1使用文本格式报文) 2.0支持对头部压缩(1.1仅 支持对body压缩) 2.0支持服务器推送,可以减少客户端请求次数。 3.5 HTTP/2.0和HTTP/3.0区别 传输协议:3.0基于QUIC(UDP升级版),提供与TLS/SSL相当的安全性 连接建立:2.0需要经过TCP三次握手外加一个TLS安全握手,需约3个RTT;而3.0由于QUIC的特性,仅需要0个或1个RTT。 队头阻塞:2.0复用一个TCP连接,一旦包丢失,会阻塞所有HTTP请求。3.0一个连接有多个不同的数据流,互不影响。 错误恢复:3.0具有更快的恢复和重传机制,2.0需要依赖于TCP的错误恢复机制。 安全加密:2.0使用TLS协议进行加密,3.0基于QUIC协议,内置加密和身份验证机制,可以提供更强的安全性。 3.6 HTTP是不保存状态的协议,那么如何保存用户状态? Session机制:通过服务端记录用户状态,时间限制到后销毁Session ...

September 26, 2024 · 4 min · 681 words · RLTEA

软件设计原则与UML类图

软件设计原则与UML类图 1 软件设计原则 开闭原则(Open Closed Principle, OCP):对扩展开发,对修改关闭 单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责 里氏替换原则(Liskov Substitution Principle, LSP):所有引用基类的地方必须能透明地使用其子类对象 依赖倒置原则(Dependency Inversion Principle, DIP):依赖于抽象,不能依赖于具体实现 接口隔离原则(Interface Segregation Principle,ISP):类之间地依赖关系应该建立在最小的接口上 合成/聚合复用原则(Composite/Aggregate Reuse Principle,C/ARP):尽量使用合成/聚合,而不是用过继承达到复用的目的 最少知识原则(Least Knowledge Principle,LKP)或迪米特法则(Law of Demeter, LOD):一个软件实体应当尽可能少的与其他实体发生相互作用。 2 UML类图 3 Spring使用了哪些设计模式 工厂设计模式:Spring使用工厂模式通过Beanfactory、ApplictionContext创建Bean对象 代理设计模式:Spring AOP功能的实现 单例设计模式:Spring中的Bean默认都是单例的 模板方法模式:Spring中jdbcTemplate、hibernateTemplate等以Template结尾对数据库操作的类 包装器设计模式: 观察者模式:Spring事件驱动模型 适配器模式:Spring AOP的增强或者通知使用到了适配器模式,Spring MVC中也使用了适配器模式适配Controller 4 JDK使用了哪些设计模式 桥接模式 适配器模式 组合模式 装饰器模式 享元模式 代理模式 抽象工厂模式 建造者模式 工厂方法 原型模式 单例模式 责任链模式 命令模式 解释器模型 中介者模式 备忘录模式 空对象模式 观察者模式 状态模式 策略模式 模板方法模式 访问者模式

September 26, 2024 · 1 min · 69 words · RLTEA

零碎知识点

零碎知识点 1 Java 原子类中,CAS是如何保证原子性的? 原子类中,用volatile修饰value,并使用unsafe类获取到value的地址偏移量,在执行更新操作时,使用unsafe类执行compareAndSwap操作,而该方法是一个Native方法,底层是通过汇编指令CMPXCHG加上Lock前缀,保证内存区域只允许一个线程访问。 2 运行时多态和编译时多态 运行时多态:通过基类或者抽象类、虚函数等调用具体实例的方法,在运行时才可以确定具体方法,这种情况时运行时多态。 编译时多态:函数的重载、模板类等,在编译时即可确定具体的方法,这种情况是编译时多态。 3 B树的具体应用 降低磁盘IO? 4 C++和Java的堆栈有什么区别 栈内存更快,但是堆内存更加灵活。 编译期间没有办法确定堆空间上的内存分配情况,堆上分配的内存需要回收(C++需要程序员手动回收,而Java有自动垃圾回收机制);而栈内存的内存回收由系统管理。 C++的对象既可以创建在堆上,也可以创建在栈上,Java绝大多数对象都创建在堆上。Java中的栈一般情况只存储引用和基本变量。 C++用alloca申请栈内存,new申请堆内存,malloc申请自由存储区,此外还有全局(静态)存储区用于存储全局变量和静态变量,常量存储区存储常量。 注意:栈中申请的内存都需要使用指针指向,Java也是如此,只不过对程序员屏蔽掉了指针。 5 C++的内存分布 由上至下分别是:栈、堆、全局区、常量区、代码区。 堆区内存向上增长,栈区内存向下增长。 https://blog.csdn.net/qq_72982923/article/details/132197354 6 Java中的对象内存分配 栈上内存分配:当对象的生命周期与入栈的方法一致时,JVM的对象逃逸分析会让该对象直接在栈上进行空间分配,从而减少GC压力 堆上内存分配:对象优先在eden区分配,大对象直接进入老年代,eden区对象经过GC后,如果存活,则存入survivor区并增加年龄,当年龄达到阈值,会进入老年代(注意:当survivor区内存不足时,会动态调整年龄阈值,将对象送入老年代)。老年代空间分配担保机制:指的是minorGC前会计算老年代剩余空间和年轻代中的对象大小,如果空间不足,则触发一次FullGC,如果垃圾回收后空间不足则会触发OOM。 7 进程的内存分配 内核区(用户不可读写)高地址段 栈(向下增长) 堆(向上增长) 数据段 代码段 https://blog.csdn.net/xyxzlsld666/article/details/132393872 8 Redis中的ListPack是什么 listpack:… :4字节,表示listpack占用字节数 :2字节,元素个数 :entry ...

September 26, 2024 · 1 min · 61 words · RLTEA