TOP ⬆

技术栈

待完善

底层

  1. 操作系统:了解内核、了进程和文件管理等重要的概念和实现方式
  2. 编译原理:粗略搞懂编译器的执行过程(汇编 √-机器码 ×)
  3. 计算机网络:彻底搞懂连网原理和 TCP/IP 的具体意义,打通网络黑箱
  4. JVM:这个底层其实还挺好奇的,目前处于黑箱状态
  5. Tomcat:热部署怎么使用的,大概了解原理
  6. 数据库高级:索引概念、视图概念、底层逻辑都不清楚其实。

应用类

  1. Vue.js:其实很好奇怎么用 MVVM 模式来进一步优化界面层啊?!借此完善自己的第一个项目

  2. Mybatis - Struct2 - SpringMVC - Spring

  3. Go 和 一些数据库的中间件

  4. 多学点 vue 写小程序

  5. SpringBoot 框架:如何实现前后端数据传输啊???

    现在已知的是三层架构模式:

    界面层

    • JSP(EL+JSTL) + JQuery + Ajax
    • SpringMVC

    业务逻辑层

    • Web (Servlet+Filter)
    • Spring

    数据访问层

    • (Druied 链接池+ JDBCUtils)DAO 模式
    • Mybatis
  6. Javaweb 注解配置(及时补充)

随记

5/14/2020 解题的思考

在解题之前先思考题目考察的内容,不要盲目地做题。先想一想、写一下文档理清思路。 YDcluQ.png

如这一道题目要求将指令复制到另一个地方,解题时首先就应该想到在哪个内存地址可以找到要复制的数据,在 8086 中 CS.dreg 指向的就是程序地址,而 di 中存放着 s 标号的地址,此时 CS:DI 就可以找到 S 标号对应的程序地址了,同理便可得目的地址。有了地址就可以考虑如何复制数据,很明显通过 mov 指令和寄存器就轻松完成了复制。

思考的关键就在于如何能快速地利用已经学过的知识来解析问题,用什么方法,需要找到什么数据(或者地址)

5/15/2020 合理计划学习任务

今天学习进度没有赶得很紧,大学课程的实验让我十分的烦恼。最近只想赶快把汇编看完然后去学 OS,自知学知识不能太赶,要一步一个脚印地来,但今天还是跳了很多个实验,寄希望于学完 OS 后再回头把实验写了,只看重理论很不好,打不下基础,我决定分批次完成实验的内容,明天把理论知识学完,然后分批完成汇编的实验和课程的实验(又把学习当任务了!!其实应该把学习时间拉长,每天只学一点但一定要完全领悟通透,只怪我脑子太笨,如今只能争取理论尽快地领悟,实验只能后补了。)唉,如果大学的课程能不那么赶而且还不要考试就好了。

有个妹妹自杀了,她的遗书写得十分平静,她所有牵挂的人和事都已经放下了,信中看不出她的绝望和痛苦,好像死亡对她来说只是一件很平常的事,她说她已经去了自己想要的很美好的地方, 突然间我开始相信我们都拥有灵魂了,相信她只是选择了另一种方式存在,愿超脱了肉体的你能永远徜徉在极乐天堂 R.I,P

时间线

五月

12 - JSON & Ajax & Javaweb_Filter

13 - 汇编语言 && 操作系统

​ 重温了汇编的寄存器部分,预计两天内看完

​ 操作系统看了 Linux 0.11 内核的系统启动过程,bochs 真难用

14 - 汇编语言

loop 指令:两步操作 1.(cx)=(cx)-1 2.判断 cx 是否为零。在 debug 中用 g + [偏移地址]可以一次性执行所有 loop

Debug 将它解释为“[idata]” 是-一个内存单元,idata 是内存单元的偏移地址; 而编译器将“[idata]” 解释为 idata 。

在汇编源程序中,数据不能以字母开头,所以要在前面加 0 直接写内存的话应当使用 0:200~0:2ff 这段空间 dos 和其他合法程序通常不会使用这段空间。

程序中的指令就要对这 8 个数据进行累加,这 8 个数据在代码段中,程序在运行的时候 CS 中存放代码段的段地址,所以可以从 CS 中得到它们的段地址。它们的偏移地址是多少呢?因为用 dw 定义的数据处于代码段的最开始,所以偏移地址为 0,这 8 个数据就在代码段的偏移 0、2、4、6、8、A、C、E 处。程序运行时,它们的地址就是 CS:0、CS:2、 CS:4、CS:6、CS:8、CS:A、 CS:C、 CS:E。 … dw 段的数据的值是多少,对于程序来说没有意义。我们定义这些数据的最终目的是,通过它们获取一定容量的内存空间,所以我们在描述 dw 的作用时,可以说用它定义数据,也可以说用它开辟内存空间。

一般在需要暂存数据的时候,我们都应该使用栈

在 8086CPU 中只有 bx si di bp 这 4 个寄存器可以用于内存单元寻址,这 4 个寄存器可以单个出现,或者以 4 种组合出现: bx+si , bx+di , bp+si , bp+di (ds:bx ss:bp) CPU 提供的如[bx+si+idata]的寻址方式为结构化处理提供了方便,用 bx 定位整个结构体,idata 定位结构体中的某一个数据项,si 定位数组项中的每个元素。可以写成 bx.idata[si]。

15 - 汇编语言

jmp 指令经典例题: Yrs7Y6.png

flag 寄存器: YsSYSP.png

CPU 提供了 cmp 指令,也提供了 je 等条件转移指令,如果将它们配合使用,可以实 现根据比较结果进行转移的功能。但这只是“如果”,只是一种合理的建议,和事实上常 用的方法。但究竟是否配合使用它们,完全是你自己的事情。这就好像 call 和 ret 指令的 关系一样。 YsAvWQ.png

8086 在内存 0000:0000 到 0000:03FF 的 1024 个单元中存放着中断向量表

18 - 操作系统 - 系统调用

**内核态和用户态:**一种处理器 “硬件设计”, DPL 目标段的特权级、CPL 当前段的特权级 当前程序执行在什么态用 CS 的最低两位来表示:0 是内核态,3 是用户态 数字越小级别越高 计算机对 CPU 是一段一段地使用,故我们可以用段寄存器来判断特权级 而 GDT 表中的表项用来描述一段内存,在操作系统段中所有的 DPL 在 GDT 中都对应内核态 当前用户使用时,根据 PC(内存段)中的 CS 段我们可以知道当前用户的 CPL,故可以判断权限

GDT/LDT 表中的描述符,描述的是一段内存。其中的 DPL 代表着 GDT/LDT 中的描述符描述的内存段的特权级别。比如,当前正在执行的代码,它的特权级别就是当前的 CS 段选择子指向的段描述符中的 DPL 所决定的。即 DPL 是描述一段内存的特权级别。

系统调用的核心:

中断处理-用户态转化成内核态最终调用内核方法 硬件提供了 INT 0x80 中断能让我们主动进入内核,最重要的就是 set_system_gate 设置中断陷阱门 set_system_gate 的参数为 INT 0x8080 中断和INT system_call表示要调用是方法,此时的 DPL 为 3; 通过转化后进入到内核态,设置 PC,其中 CS 为 8(100)故可得 CPL 为 0 内核态,而 IP 为 system_call 通过查 system_call_table 得到 _NR_XXX 最终调用 sys_XXX

调用的具体过程: 用户调用 XXX 方法 通过库函数展开成宏,调用中断 中断处理 system_call 查 sys_call_table 得到

19 - 操作系统 - 进程管理(CPU 部分)

CPU 使用的关键是:取值执行 设置完 PC 后便自动开始工作,但这样顺序执行有很多缺点:但程序需要调用 IO 设备或者磁盘时,会等待很久从而造成时间上的浪费,于是我们需要让 CPU 交替执行多个程序

一个 CPU 上交替执行多个程序称为:并发,在交替执行的时候为了完成切换需要保存寄存器等程序信息,从而引入进程(进行中的程序)的概念,CPU 在运行多个程序时跑多个进程,因此 CPU 运行的效率得到大大提升

多进程图像: CPU 用 PCB(Process Control Block 记录进程信息的数据结构) 进程带动内存的使用需要用映射表(MMU)进行内存封存 - 同一地址指向不同物理地址 - 为了共存;

多线程:- TCB 线程控制表 线程有自己的 TCB,thread control block, 只负责这条流程的信息,包括 PC 程序计数器,SP 堆栈,State 状态,和寄存器。有不同的控制流,需要不同的寄存器来表示控制流的执行状态,每个线程有独立的这些信息,但共享一个资源。

多核:线程-用户栈和内核栈-进程切换 每个线程对应一套栈,用户栈和内核栈 用户栈进入内核栈:系统调用(fork())会引起中断并且创建一个进程,有两个重点: 1.一个线程是怎么通过进程切换的 2.创建一个进程需要做哪些准备 线程切换五段论:中断入口,建立用户栈和内核栈的联系 进入内核态执行,执行完毕过程中或者执行完毕后,系统会判断事件有可能引发切换(中间三段) 中断返回 ret_from_sys_call

创建进程的任务就开始了 ThreadCreate:

执行我们想要的代码:

20 - 操作系统 - 调度算法 - 进程合作

调度算法 - IO 约束型和 CPU 约束型

**IO 约束型:**通常优先级会比较高,提前调用 IO 可以让设备先处理,CPU 可以并发执行,等待设备处理完后 CPU 读数据就行 此时是 read 中断,对应的通常是前台进程(用户进程) **CPU 约束型:**用的 TimeOut 中断,对应的通常是后台进程

一个好的调度算法(Schedule())应该折中、会自适应、能自动分辨前后台进程、以 RR(轮转调度算法)为核心、有优先级。具体实现方式是:

进程合作 - 多个进程共同完成一个任务 - 信号量

COUNT 信号已经无法简单处理了多个进程等待和资源生产复杂情况了,需要一个信号量来实现“走走停停”,信号量里有 value(资源的个数)和 PCB 阻塞队列(等待在该信号量上的进程),信号量中 P 操作是消费资源,V 操作是生产资源。

信号量解生产者-消费者问题: 生产者第一步 P(empty)需要判断资源是否满了,满了则不能再生产了,empty= 0 表示缓冲区满了,消费者的第一步 P(full)则是判断当前已经生产的个数,为零则无法消费,full 表示已经生产的个数;第二步两者都是上锁 P(mutex),然后分别执行读入写出,最后解锁 V(mutex);生产者第三步是 V(full) 代表生产了一些资源,而消费者是 V(empty) 消耗了一些资源

信号量需要临界区来保护,因为信号量是所以进程共享的。 临界区保护原则:

信号量的具体实现过程:面包算法、关中断方法、原子指令上锁法 在内核中为用于一个数组存放信号量,再建立队列用于存放 PCB,因为是全局数据所以要写在内核中,用的时候必须使用系统调用队列中对应的信号量

死锁处理:PC 机通常使用死锁忽略

21 - 操作系统 - 内存管理

内存使用和分段:

要从逻辑地址转化成物理地址用运行时重定位最合适,利用的基址放在 PCB 中,执行指令时第一步就是从 PCB(特殊数据结构,其中包含了GDTLDT)中取出基地址

由于程序是分段的 code segment | data segment … 方便管理而且在载入时节约资源,所以在存放基地址时还需要按段号分段存放到 DS 中,形成进程段表。 操作系统的段表就是GDT,子进程的段表是LDT(LDT 可以看成是 GDT 分配的)

地址翻译的具体实现过程是:首先找到本段的程序段号,然后在 LDT 表中的找到对应的基地址,完成重定位过程,段号存放在 ldtr 中

内存分页

分区是为了能找到空闲的内存区并管理内存,这样在进程载入的时候才找得到空闲内存区,分段分区都是针对的虚拟内存。但分区会产生很多碎片,因此我们采用分页

一个程序有很多段,一个段又对应很多页 用页表实现分页,页表起始地址放在 cr3 通过 MMU 得到页号,页号找到页框号,最后将页框号和逻辑地址相连,页框规定了页的大小,页表存放在 PCB 中,每个进程都有自己的页表

段页内存同时存在:

程序用段-虚拟内存-虚拟内存分页-映射到物理内存 段页同时存在时的重定位(地址翻译): 段依旧按段表找出基地址加上段偏移得到虚拟地址-再从虚拟地址映射到页表找到页号,利用页号和偏移地址得到物理地址,两层地址翻译:段号到虚拟地址、页号到物理地址

备忘录

深入

底层 - 汇编:(王爽《汇编语言第三版》)

3.7 CPU 提供的栈机制

入栈和出栈都是以字为单位,通过 SS 段寄存器:SP 寄存器 来指向栈顶元素

栈是从高地址往低地址增长的,这同时解决了“CPU 如何知道此段内存空间是栈“的问题,当 SP 寄存器 负增长的底线是 0000h,故定义起始地址后栈大小也随之确定。但 CPU 是不会保证我们对栈的操作不会越界的,POP 和 PUSH 的过程中有可能会产生溢出

当栈为空时 SS:SP 指向栈空间最高地址单元的下一个单元

​ 我们当然希望 CPU 可以帮我们解决这个问题,比如说在 CPU 中有记录栈顶上限和栈 底的寄存器,我们可以通过填写这些寄存器来指定栈空间的范围,然后,CPU 在执行 push 指令的时候靠检测栈顶上限寄存器、在执行 pop 指令的时候靠检测栈底寄存器保证不 会超界。 ​ 不过,对于 8086CPU,这只是我们的一个设想(我们当然可以这样设想,如果 CPU 是 我们设计的话,这也就不仅仅是一个设想)。实际的情况是,8086CPU 中并没有这样的寄 存器。 ​ 8086CPU 不保证我们对栈的操作不会超界。这也就是说,8086CPU 只知道栈顶在何 处(由 SS:SP 指示),而不知道我们安排的栈空间有多大。这点就好像 CPU 只知道当前要执 行的指令在何处(由 CS:IP 指示),而不知道要执行的指令有多少。从这两点上我们可以看 出 8086CPU 的工作机理,它只考虑当前的情况:当前的栈顶在何处、当前要执行的指令 是哪一条。 ​ 我们在编程的时候要自己操心栈顶超界的问题,要根据可能用到的最大栈空间,来安 排栈的大小,防止入栈的数据太多而导致的超界;执行出栈操作的时候也要注意,以防栈 空的时候继续出栈而导致的超界。

应用层 - JavaWeb_Filter & Ajax & JSON