diff --git a/C++/标准库/12 动态内存.md b/C++/标准库/12 动态内存.md index 1fe459ff..5818b75c 100644 --- a/C++/标准库/12 动态内存.md +++ b/C++/标准库/12 动态内存.md @@ -247,7 +247,7 @@ alloc.deallocate(p,n) 2. 调用对象构造函数构造对象内容 * delete运算分两个阶段: - 1. 调用对象希构函数; + 1. 调用对象析构函数; 2. 调用::operator delete释放内存 * 为了精密分工,STL allocator将两个阶段操作区分开来:内存配置有alloc::allocate()负责,内存释放由alloc::deallocate()负责;对象构造由::construct()负责,对象析构由::destroy()负责。 diff --git a/工作日志/2021年8月31日-九月份计划.md b/工作日志/2021年8月31日-九月份计划.md index e078ea22..f5526ba2 100644 --- a/工作日志/2021年8月31日-九月份计划.md +++ b/工作日志/2021年8月31日-九月份计划.md @@ -57,6 +57,7 @@ * 流程 * [x] 居然智能车捞起来了,着实,不太行。 * [x] 腾讯笔试:09-05 20:00:00 -- 22:00:00https://qq.nowcoder.com/cts/17036433/summary?id=B2EAF4DC35F7F779 + * [ ] 腾讯一面 2021-09-10 10:30 https://meeting.tencent.com/dm/mJj5W3u5jns4 ### 百度 @@ -76,7 +77,9 @@ * [x] 建立投递https://talent.baidu.com/external/baidu/campus.html#/individualCenter * [x] 百度一面2021-08-30 14:00-15:00:https://code.meideng.net/ykl1 * [x] 建立共享当中,应该是面试挂掉了 - * [ ] 新的笔试(都挂了,不应该啊)2021年-09-07 19:00:00 -- 21:00:00 + * [x] 新的笔试(都挂了,不应该啊)2021年-09-07 19:00:00 -- 21:00:00 + * [ ] 2021-09-11 16:00百度一面 9-11 16:00-17:00 + * [ ] @@ -117,7 +120,7 @@ * [x] 美团一面:北京时间08月31日 19:00,面试类型:视频面试,面试地址:http://dpurl.cn/0wnxIGBz * [x] 美团二面:北京时间09月02日 14:00,http://dpurl.cn/4knwRG4z * [x] 美团三面:北京时间09月06日 10:30。电话面试。我跟面试官同时忘记了面试时间。 - * [ ] 美团三面。北京时间09月07日 15:30。电话面试。 + * [x] 美团三面。北京时间09月07日 15:30。电话面试。 ### 网易 * 岗位: @@ -198,7 +201,8 @@ * [x] 建立投递。官网烂的一批。https://app.mokahr.com/campus_apply/xiaomi/286#/job/dc8d7233-d059-4df9-938d-c0a01be881f7 * [x] 要做测评(邮箱里有测评的链接。)\ * [x] 在线笔试2021-09-01 19:00 星期三https://mi.acmcoder.com/cand/login?673rqtpa - * [ ] 小米面试。9月8日-15.00-17.00 + * [x] 小米面试。9月8日-15.00-17.00 + * [ ] 小米二面。09月09日面试时间:16:00 ### vivo diff --git a/工作日志/2021年9月8日-今日计划.md b/工作日志/2021年9月8日-今日计划.md new file mode 100644 index 00000000..de1d215c --- /dev/null +++ b/工作日志/2021年9月8日-今日计划.md @@ -0,0 +1,20 @@ +## 任务 + + +上午 +* [x] 看完操作系统 +* [x] 看完计算机网络 +* [ ] 再复习一遍数据库 + +下午 +* [ ] 复习数据结构 + +晚上 + +* [ ] 复习算法 +* [ ] 完成建立投递 + +明天开始之后的任务 + +* [ ] 刷题总结 +* [ ] 看面经 \ No newline at end of file diff --git a/操作系统/5.5 IO多路复用与回调函数.md b/操作系统/5.5 IO多路复用与回调函数.md index 6d22b74c..80867386 100644 --- a/操作系统/5.5 IO多路复用与回调函数.md +++ b/操作系统/5.5 IO多路复用与回调函数.md @@ -8,34 +8,33 @@ this 不是指向类。而是在实例化的时候与当前类的实例也就是 ### 关于回调 -对于Python与JavaScript这种,能够直接传递“函数类型”的参数的语言,回调函数可以作为另外一个函数的参数,进行传递。(C++也是可以传递函数指针的) - -在C++和java这种只能传递基本数据类型和构造数据类型的语言中,即函数不作为数据类型的语言中,可以通过传递整个对象的方法,使得被调用者,能够通过调用者对象的指针,进行回调,这也是设计模式的一种。(观察者模式?) +对于Python与JavaScript这种,能够直接传递“函数类型”的参数,C++也是可以传递函数指针和可调用对象,java能够传递对象引用进而调用对象内部的函数。回调函数可以作为另外一个函数的参数,进行传递。 -关于回调函数的本质理解:当其他程序执行时,能够通过回调函数,转移进程控制权限,给调用者(这里并没有转移控制权,而是保留控制权在本地,完成不可知的后续处理)。可以把调用者与被调用者分开。调用者能够显式调用被调用者,同时被调用这能通过回调函数隐式调用调用者。但是实在另一个线程中执行。 -关于回调函数的本质理解:回调函数在同一个层次内是没有用的,或者说没有必要的。如果一个人,在实现一个层次内部的函数执行权限转移过程中,可以直接进行相互调用,因为本质上,两个部分是完全可知的。但是在不同层次的调用中,例如用户层与系统层中,用户层调用系统层,可以通过显式调用,但是系统层并不会考虑用户层的具体实现,对用户层是不可知的。这个时候,系统层会通过传递来的回调函数,将进程控制权交给用户层。(并不会转移控制权,交给其他的线程) +关于回调函数的本质理解:当其他程序执行时,能够通过回调函数,执行调用者的代码,访问调用者传递进来的资源。但这里并没有转移控制权,而是保留控制权在当前的被调用者。可以把调用者与被调用者分开。调用者能够显式调用被调用者,同时被调用这能通过回调函数隐式调用调用者。 + +### 同步回调与异步回调 + +回调函数在同一个线程或进程内,是同步回调,调用者与被调用这的CPU控制权是串行的。回调函数的主要目的是业务逻辑的划分,降低调用者和被调用者,相互调用时的耦合程度。也就是说,不同的调用者,可以让被调者在某一阶段。 + + +当回调函数与主调函数的执行不再同一个线程内,是异步回调,调用者与被调用者的CPU控制权是并行的。被调函数就可以通过回调函数完成后续的处理,而不需要中断主调函数。这也是actor设计模式的原则之一。 + + + +### 回调作用 那么问题来了,直接通过返回值的方式转移进程的控制权限不好吗。在回调的部分通过返回值,区分不同的情况,用户自己选择执行什么样的函数。 -首先允许我,在这里将程序简单地分为用户层和系统层。用户层就是程序员编写的代码,系统层就是程序语言提供的外部库、框架、工具等。 +首先将程序简单地分为用户层和系统层。用户层就是程序员编写的代码,系统层就是程序语言提供的外部库、框架、工具等。 -关于回调函数的本质理解:回调函数在单线程的编程中也有一定的作用。在之前的疑问中,用户根据返回值调用不同的函数与系统调用回调函数与系统通过回调函数调用用户程序,后者,当回调程序执行完成后控制权依旧交给系统,不必考虑,系统在什么地方中断。在这里涉及一个关键的问题,到底是用户具有主动权还是系统具有主动权。在架构设计中有一个很关键的问题,系统应该提供大量的类、方法等工具,帮助用户实现一个完成的程序,还是系统应该实现主体的程序,在特定情况下调用用户的程序实现局部功能? +关于回调函数的本质理解: -关于这个问题的讨论,我想应该牵扯到系统架构相关的很多知识,我觉得有空多读点专业类的书籍还是很有帮助的。理论书籍。要远比自己单纯的了解技术和知识好的多。 +回调函数在单线程的编程中也有一定的作用。在之前的疑问中,用户根据返回值调用不同的函数与系统调用回调函数与系统通过回调函数调用用户程序,后者,当回调程序执行完成后控制权依旧交给系统,不必考虑,系统在什么地方中断。在这里涉及一个关键的问题,到底是用户具有主动权还是系统具有主动权。在架构设计中有一个很关键的问题,系统应该提供大量的类、方法等工具,帮助用户实现一个完成的程序,还是系统应该实现主体的程序,在特定情况下调用用户的程序实现局部功能? -我想关于上边的问题,应该可以非常好的区分编程框架与库的区别。比如jQuery就是编程库,它提供了功能。springboot是编程框架,它提供了主体流程,用户只要实现少量的自定义模块,而不需要管理程序的一级一级调用过程。 -简单来说,用户只要通过少量的注解,就能将自己的类注册到spring框架当中,用户完成的知识其中的一笑部分补充代码。 +* 编程框架与库的区别。比如jQuery就是编程库,它提供了功能,主体流程需要自己控制。springboot是编程框架,它提供了主体流程,用户只要实现少量的自定义模块,而不需要管理程序的一级一级调用过程。 -简单举例,假如我想要设计一个编程框架,这个框架是想要提供可以复用的功能,还是想完成主要的流程呢? +* 简单来说,用户只要通过少量的注解,就能将自己的类注册到spring框架当中,用户完成的知识其中的一笑部分补充代码。简单举例,假如我想要设计一个编程框架,这个框架是想要提供可以复用的功能,还是想完成主要的流程呢? -我之前觉得仿真程序的开发,不好的原因是扩展性、可读性、重用性都十分差,所以,从工程的角度来说,这些代码确实需要重构。 - -那么通过什么样的方式实现代码重构呢?最终的要的办法是实现模块化,将所有的功能模块化,并提供统一的标准接口,规范命名等。 - -另一个很重要的内容,是构建新的编程框架。使每一个开发人员都专注于搞算法和逻辑,而不是在无休止的重复尝试。写一堆无用的重复的逻辑代码。 - -模块化,提供编程的API,实现各种可以重复使用的功能。 -编程框架,编程模型,实现主要的业务流程,作为系统层,用户通过注入的方式,将自己身构建的代码添加到系统流程中。系统通过回调的方式,实现特殊情况的处理。 diff --git a/操作系统/Linux系统分析.md b/操作系统/Linux系统分析.md deleted file mode 100644 index 32c6af8b..00000000 --- a/操作系统/Linux系统分析.md +++ /dev/null @@ -1 +0,0 @@ -## \ No newline at end of file diff --git a/操作系统/image/2021-09-08-19-48-06.png b/操作系统/image/2021-09-08-19-48-06.png new file mode 100644 index 00000000..869fcd0f Binary files /dev/null and b/操作系统/image/2021-09-08-19-48-06.png differ diff --git a/操作系统/image/2021-09-08-19-53-05.png b/操作系统/image/2021-09-08-19-53-05.png new file mode 100644 index 00000000..e85d20a1 Binary files /dev/null and b/操作系统/image/2021-09-08-19-53-05.png differ diff --git a/操作系统/image/2021-09-08-19-55-03.png b/操作系统/image/2021-09-08-19-55-03.png new file mode 100644 index 00000000..dc32fd85 Binary files /dev/null and b/操作系统/image/2021-09-08-19-55-03.png differ diff --git a/操作系统/附录10 动态内存的原理.md b/操作系统/附录10 动态内存的原理.md index c74cfd76..4e0efdc6 100644 --- a/操作系统/附录10 动态内存的原理.md +++ b/操作系统/附录10 动态内存的原理.md @@ -68,16 +68,18 @@ SECTIONS { -​Linux动态内存分配的实现方式是由 mmap, munmap 以及 brk, sbrk 这四个系统函数联合完成的。 +​Linux动态内存分配的实现方式是由 mmap与munmap和brk与sbrk 这四个系统函数联合完成的。 -### mmap +这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。 + +### mmap&munmap ``` void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); ``` -mmap 创建一个新的虚拟内存空间和文件设备之间的映射。 +mmap 创建一个新的虚拟内存空间和文件设备之间的映射。其中,mmap内存映射文件是在堆和栈的中间。 ![](image/2021-09-07-18-46-05.png) @@ -98,7 +100,7 @@ MAP_SHARED // 共享的 ``` -### munmap + 取消相应地址内存块的映射 ``` @@ -127,3 +129,70 @@ void *sbrk(intptr_t increment); ## 4 malloc和alloc的原理 +在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的 + +### malloc < 128K +* malloc小于128k的内存,使用brk分配内存,将_edata往高地址推(只分配虚拟空间,不对应物理内存(因此没有初始化),第一次读/写数据时,引起内核缺页中断,内核才分配对应的物理内存,然后虚拟地址空间建立映射关系) + +> 这个图例的高地址和低地址反了 + +![](image/2021-09-08-19-48-06.png) + +1. 进程启动的时候,其(虚拟)内存空间的初始布局如图1所示。_edata指针(glibc里面定义)指向数据段的最高地址。 +2. 进程调用A=malloc(30K)以后,内存空间如图2: + 1. malloc函数会调用brk系统调用,将_edata指针往高地址推30K,就完成虚拟内存分配。你可能会问:只要把_edata+30K就完成内存分配了? + 2. 事实是这样的,_edata+30K只是完成虚拟地址的分配,A这块内存现在还是没有物理页与之对应的,等到进程第一次读写A这块内存的时候,发生缺页中断,这个时候,内核才分配A这块内存对应的物理页。也就是说,如果用malloc分配了A这块内容,然后从来不访问它,那么,A对应的物理页是不会被分配的。 +3. 进程调用B=malloc(40K)以后,内存空间如图3。 + + + +### malloc > 128K + +malloc大于128k的内存,使用mmap分配内存,在堆和栈之间找一块空闲内存分配(对应独立内存,而且初始化为0),如下图: + +> 这个图例的高地址和低地址反了。 + +![](image/2021-09-08-19-53-05.png) + +1. 进程调用C=malloc(200K)以后,内存空间如图4: + 1. 默认情况下,malloc函数分配内存,如果请求内存大于128K(可由M_MMAP_THRESHOLD选项调节),那就不是去推_edata指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存。这样子做主要是因为:: + 2. brk分配的内存需要等到高地址内存释放以后才能释放(例如,在B释放之前,A是不可能释放的,这就是内存碎片产生的原因,什么时候紧缩看下面),而mmap分配的内存可以单独释放。 +2. 进程调用D=malloc(100K)以后,内存空间如图5; + +### free +进程调用free(C)以后,C对应的虚拟内存和物理内存一起释放。 +![](image/2021-09-08-19-55-03.png) + + +1. 进程调用free(B)以后,如图7所示: + 1. B对应的虚拟内存和物理内存都没有释放,因为只有一个_edata指针,如果往回推,那么D这块内存怎么办呢? + 2. 当然,B这块内存,是可以重用的,如果这个时候再来一个40K的请求,那么malloc很可能就把B这块内存返回回去了。 +2. 进程调用free(D)以后,如图8所示:B和D连接起来,变成一块140K的空闲内存。 +3. 默认情况下:当最高地址空间的空闲内存超过128K(可由M_TRIM_THRESHOLD选项调节)时,执行内存紧缩操作(trim)。在上一个步骤free的时候,发现最高地址空闲内存超过128K,于是内存紧缩,变成图9所示。 + +### malloc的实现方案 +1. malloc 函数的实质是它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。 +2. 调用 malloc()函数时,它沿着连接表寻找一个大到足以满足用户请求所需要的内存块。 然后,将该内存块一分为二(一块的大小与用户申请的大小相等,另一块的大小就是剩下来的字节)。 接下来,将分配给用户的那块内存存储区域传给用户,并将剩下的那块(如果有的话)返回到连接表上。 +3. 调用 free 函数时,它将用户释放的内存块连接到空闲链表上。 +4. 到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段, 那么空闲链表上可能没有可以满足用户要求的片段了。于是,malloc()函数请求延时,并开始在空闲链表上检查各内存片段,对它们进行内存整理,将相邻的小空闲块合并成较大的内存块。 + + + + + +### 总结 + +brk和mmap: + +从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。 + +1. brk是将数据段(.data)的最高地址指针_edata往高地址推; +2. mmap是在进程的虚拟地址空间中(堆和栈中间,称为文件映射区域的地方)找一块空闲的虚拟内存。这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。 + +在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的。 + + + + + + diff --git a/操作系统/附录2 操作系统总结.md b/操作系统/附录2 操作系统总结.md index 49e9a326..2d3e887d 100644 --- a/操作系统/附录2 操作系统总结.md +++ b/操作系统/附录2 操作系统总结.md @@ -27,7 +27,7 @@ * 复用和虚拟的主要目标是解决**物理资源数量不足的问题**,抽象则用于处理系统复杂性,重点**解决资源易用性**。 ## 2 系统调用 -* 系统调用: 为给应用程序的运行提供良好环境,内核提供了一系列具有预定功能的服务例程,通过一组称为**系统调用(System Call)**的接口呈现给用户,系统调用把应用程序的请求传送至内核,调用相应的服务例程完成所需处理,将处理结果返回给应用程序。(注:系统调用的编号称为功能号) +* 系统调用: 为给应用程序的运行提供良好环境,内核提供了一系列具有预定功能的服务例程,通过一组称为**系统调用(System Call)** 的接口呈现给用户,系统调用把应用程序的请求传送至内核,调用相应的服务例程完成所需处理,将处理结果返回给应用程序。(注:系统调用的编号称为功能号) ![](image/2021-03-29-18-57-45.png) diff --git a/计算机网络/2.1 应用层-协议原理.md b/计算机网络/2.1 应用层-协议原理.md index 796153d7..d4377eeb 100644 --- a/计算机网络/2.1 应用层-协议原理.md +++ b/计算机网络/2.1 应用层-协议原理.md @@ -1,4 +1,4 @@ -# 应用层协议原理 + # 应用层协议原理 ## 1 网络应用程序体系结构 diff --git a/计算机网络/2.2 应用层-HTTP.md b/计算机网络/2.2 应用层-HTTP.md index f55011f0..af9a37f5 100644 --- a/计算机网络/2.2 应用层-HTTP.md +++ b/计算机网络/2.2 应用层-HTTP.md @@ -138,7 +138,24 @@ HTTP 是无状态的,但是 Web 站点通常希望能够识别用户,为此 ![](image/cookie工作流程.png) -## 5 web缓存Cache +## 5 Http Session +服务器会为每一个用户 创建一个独立的HttpSession + +HttpSession原理 +1. 当用户第一次访问Servlet时,服务器端会给用户创建一个独立的Session并且生成一个SessionID,这个SessionID在响应浏览器的时候会被装进cookie中,从而被保存到浏览器中 +2. 当用户再一次访问Servlet时,请求中会携带着cookie中的SessionID去访问服务器会根据这个SessionID去查看是否有对应的Session对象有就拿出来使用;没有就创建一个Session(相当于用户第一次访问) + +域的范围: +1. Context域 > Session域 > Request域 +2. Session域 只要会话不结束就会存在 但是Session有默认的存活时间(30分钟) + +### session进行身份验证的原理: + +1. 当客户端第一次访问服务器的时候,此时客户端的请求中不携带任何标识给服务器,所以此时服务器无法找到与之对应的session,所以会新建session对象,当服务器进行响应的时候,服务器会将session标识放到响应头的Set-Cookie中,会以key-value的形式返回给客户端,例:JSESSIONID=7F149950097E7B5B41B390436497CD21;其中JSESSIONID是固定的,而后面的value值对应的则是给该客户端新创建的session的ID, +2. 之后浏览器再次进行服务器访问的时候,客户端会将此key-value放到cookie中一并请求服务器,服务器就会根据此ID寻找对应的session对象了;(当浏览器关闭后,会话结束,由于cookie消失所以对应的session对象标识消失,而对应的session依然存在,但已经成为报废数据等待GC回收了)对应session的ID可以利用此方法得到:session.getId(); + + +## 6 web缓存Cache ### 原理 * Web缓存器也叫代理服务器,是能够代表 Web 服务器来满足 HTTP请求的网络实体。 * Web 服务器有自己的磁盘存储空间,并在存储空间中保存着最近存储过的对象的副本。