../img/avatar.png

This Tinggeng

一张思维导图看操作系统 【持续迭代】

概述 总结自己的操作系统的知识,按照编码 -> 运行,画了一张图,xmind 导出的图比较大,目前这部分的内容还比较少,后续持续更新,迭代这部分的内容。 下面是一些常见的知识,将会慢慢补充进思维导图内 linux 整体结构图 makelinux:makelinux 解释器 & 编译器 & JIT & AOT 参考链接1 参考链接2 JIT(Just In Time)和 AOT(Ahead Of Time)是两种不同的编译方式: JIT: 编译时,将源代码编译成字节码(bytecode),运行时再将字节码编译成机器码。 优点是运行时可以进行更多优化,生成更高质量的机器码。 缺点是编译时需要额外的编译步骤,会增加程序启动时间。 第一次运行时编译时间较长,后续运行时间短。运行时性能较AOT略差。 AOT: 编译时,将源代码直接编译成机器码。 优点是编译只有一次,程序启动更快。 编译器在程序运行前完成编译,生成机器代码。运行时直接执行机器代码。 编译时间较长,运行时性能好。 改动源代码需要重新编译。 缺点是编译时难以进行复杂的优化,生成的机器码质量可能较低。 典型的AOT编译语言有C、C++等。 总结: JIT 的运行性能更高,但启动时间长。适合长时间运行的程序。 AOT 的启动时间短,但运行性能可能略低。适合启动频繁的程序。 在实际使用中,也可以二者结合,采用 AOT 先编译成机器码,再运行时由 JIT 进一步优化,以兼顾启动时间和运行性能。许多语言(如 Java、C#)的编译器都支持这两种模式。 ![[Pasted image 20230407143623.png]] 解释器:Java源程序编译成字节码,然后由运行环境对字节码解释执行,提供解释功能的 JVM 组件为解释器。它能执行 JVM 规范的字节码,执行方式是一遍翻译一遍执行,所以效率低,但是简单并易于实现。主要实现是在 Interpreter 模块。 ![[Pasted image 20230407143647.png]] 即时编译器:能够将运行时的热点代码,编译成运行效率高的及时代码。 判断一段代码是不是热点代码,是不是需要触发JIT编译,这样的行为称为:热点探测(Hot Spot Detection),有几种主流的探测方式: 基于计数器的热点探测(Counter Based Hot Spot Detection):虚拟机会为每个方法(或每个代码块)建立计数器,统计执行次数,如果超过阀值那么就是热点代码。缺点是维护计数器开销。 基于采样的热点探测(Sample Based Hot Spot Detection):虚拟机会周期性检查各个线程的栈顶,如果某个方法经常出现在栈顶,那么就是热点代码。缺点是不精确。 基于踪迹的热点探测(Trace Based Hot Spot Detection):Dalvik中的JIT编译器使用这种方式 JIT 是可以回退到解释器执行的 inlining 内联(最关键的优化手段) inlining 指在编译时,识别 call site (持有 method handle 的对象) 的目标方法,将其方法体 加入当前方法的编译范围,并将其结果替换掉原 call site,比如 getter 和 setter 就会优化为一条访问内存的指令。

一张思维导图看网络【持续迭代】

概述 受到《计算机网络-自顶向下方法》 的启发,按照网络请求的过程,总结自己的网络知识,按照时间线,画了一张图,xmind 导出的图比较大,后续持续更新,迭代这部分的内容。 下面是一些常见的知识,将会慢慢补充进思维导图内 输入 url 到页面展示,经历的过程 参考链接1 参考链接2 url 解析,提取 host; DNS 解析 匹配浏览器的 DNS 的缓存; 匹配 Host 文件; 匹配系统的 DNS 缓存; 系统向本地 DNS 服务器发送请求; 联网时候,系统会自动发送 DHCP Request,路由器收到这个广播后,会向电脑分配一个地址,这个地址就是 DNS 服务器的地址; 可以通过抓包看; 通过设置中心; 通过生成的临时文件查看; DNS 通过 DNS 迭代查询 查询域名的 ip 地址; DNS 服务器返回多个地址组合,浏览器根据 DNS 轮转策略 选择一个 IP 地址进行请求; 这个过程在各个 socket 库中都有系统实现; 委托系统网络协议栈发送请求数据 创建 socket 套接字; 套接字是内存中的一块内存,其中保存了通信的控制信息; 一个套接字对应了一个端口,用以区分不同的 socket 套接字; 将 socket 连接到 server;三次握手 发送数据; 协议栈不关心应用程序传来的数据内容。在它看来,要发送的数据就是一段二进制字节序列而已。 协议栈并不会在收到数据后马上发出,而是需要判断几个要素后决定是否发出: 当协议栈缓冲区中存在的数据长度超过或接近 MSS 时会将包发出。 在收到一段数据后缓冲区会开启一个计时器,经过一定时间后仍未有新数据包产生则将缓冲区内容发出。 如果应用程序指定了“立刻发出”,那么协议栈就会按照要求直接发送数据。(一般像浏览器这种会话型的应用程序在向服务器发送数据时,等待填满缓冲区会导致延迟影响用户体验,因此一般会要求协议栈直接发出) MTU:一个网络包的最大长度,以太网中一般为1500字节。 MSS:除去头部之后,一个网络包所能容纳的TCP数据的最大长度。 接收数据 首先,协议栈尝试从接收缓冲区中取出数据并传递给应用程序,但这个时候请求消息刚刚发送出去,响应消息可能还没返回。响应消息的返回还需要等待一段时间,因此这时接收缓冲区中并没有数据,那么接收数据的操作也就无法继续。这时,协议栈会将应用程序的委托,也就是从接收缓冲区中取出数据并传递给应用程序的工作暂时挂起,等服务器返回的响应消息到达之后再继续执行接收操作。 协议栈接收到数据会会检查收到的数据块和 TCP 头部的内容,判断包是否合法可用,如果没问题则返回 ACK 确认号。然后将数据块暂存到缓冲区中,并拼接数据还原原始数据。 数据包恢复原样后将会将数据复制到应用程序指定内存地址后将控制流程转交回应用程序。然后再寻找合适时机进行窗口更新。 断开连接;四次挥手 删除套接字 DNS 作用 域名解析,将网址中的域名解析成协议栈的 IP 地址。

一张思维导图看 Android【持续迭代】

概述 总结自己的 Android 知识,按照编码 -> 运行,画了一张图,xmind 导出的图比较大,后续持续更新,迭代这部分的内容。 下面是一些常见的知识,将会慢慢补充进思维导图内 Handler 与 Binder handler 处理的是 App 进程内的通信; binder 处理的是,App 进程间、application 和 framework 之间的通信; 任务启动管理 - 启动框架 抽象任务 task; 优先级 ; countdownlatch 数值为依赖 task 的数量; 运行的 executor ; 被依赖的 task 列表; toWait 方法; notify 方法,countdownlatch 减一; 构造 task 的有向无环图; TaskManager: 管理所有的 task,及其拓扑关系; 管理需要执行的 task; countdownlatch 值为 Activity 跳转的生命周期 ActivityA跳转到ActivityB: 1 2 3 4 5 Activity A:onPause Activity B:onCreate Activity B:onStart Activity B:onResume Activity A:onStop ActivityB返回ActivityA: 1 2 3 4 5 6 Activity B:onPause Activity A:onRestart Activity A:onStart Activity A:onResume Activity B:onStop Activity B:onDestroy 旋转屏幕 不改配置,默认配置 1 2 3 4 5 6 7 onPause--> onStop--> onDestroy--> onCreate--> onStart--> onRestoreInstanceState--> onResume--> 修改配置 1 onConfigChanged--> Activity 的启动模式 参考链接1

文档系统_程序员如何写好文档 (The documentation system)

背景 文档是日常开发过程中非常重要的记录和交流的工具,也是学习新技术必然要阅读的材料.学习技术的时候,都会建议直接看官方文档,不同的技术网站,会看到 Guide,Tutorial,Wiki,Reference 等分类(也可能只包含其中一个或者几个). 我之前就一直对这几个英文单词有疑问,尤其是我在看 Android 开发者官网的时候,不明白每个分类的依据,间接导致,自己也没有学会如何写文档.后来发现了这篇文章,读完觉得很有道理. The documentation system,窃以为非常好,值得我进行模仿学习. 以下的内容会进行自我理解的翻译,有意无意的删除一些冗余的修辞,如有幸被网上邻居搜到,建议看原文,非常简单. Summary 为了编写良好的软件文档,需要说一个秘密: 没有一个名为文档的东西,文档应该是四样东西的集合. 这四样分别是是:tutorials(教程),how-to guides(如何做的引导),technical reference (技术参考),explanation(解释). 它们代表四种不同的目的或职能,并且这四种的写作方式都有差异.了解了这些差异,通常能巨大的提高文档的质量. 关于即将描述的文档系统 这里的文档系统是非常简单的,近乎于全面适用行业内的方案.行文有个承诺: 如果将这些原则在实践中进行应用,将极大的提高写作文档的质量. 有很多公司/组织/开源项目采用了本文所述的方案,详细见链接采用本方案的项目 Introduction 问题和解决方案 需要解决的问题 如果文档不够好,产品再好,人们也不会使用它.即使人们必须使用它,那也是因为他们别无选择,没有良好的文档,人们无法如你期望的那样使用你开发的产品. 当然了,每个人都知道文档的重要性,每个人也都尝试去写好文档,最终也都失败了. 这也不是写作的人不够努力,通常是他们没有按照正确的方式去做而已. 本文介绍的文档系统,不是为了让你更加努力的工作,而是让你写作的文档更好,使用正确的方式进行写作,让文档更加易懂,更加容易维护: The right way is the easier way. 文档系统的秘密 有一个不应该是秘密的秘密: 文档应该围绕四种不能的功能目的进行构造: tutorials(教程),how-to guides(如何做的引导),technical reference (技术参考),explanation(解释).每一种都需要有独立的写作模式. 软件的使用者在不同的情况下,需要不同的文档,故而,大部分的软件,对于这四种文档,都需要包含. 文档将围绕这四种进行构建,并且四种文档需要独立的创建. Tutorials(教程) How-to guides(如何做的引导) Reference(技术参考) Explanation(解释) oriented to(面向的/目的/导向) 学习 有一个固定的目标 传达信息 为了更深的理解 must (必须做到) 让一个初学者上手 演示如何解决一个特定的问题 描述技术的内部参数等 深层次的解释 its form(形式) 一节课 一些列的步骤 纯粹的描述 用文字进行阐述说明 analogy(类比) 教一个孩子如何进行烹饪 烹饪中的食谱 百科全书里的文章 关于烹饪的历史书 如上这种划分,可以让作者清楚写什么内容,写在哪儿,如何写; 读者清楚去哪找想要的内容.

mySoftware

概述 记录我平时使用的一些软件,提效的,娱乐的. 快速打开 Raycast Alfred Contexts 目的: 用于快速打开应用软件和文件夹 其中比较知名的就是 Alfread了,我目前把它和Context进行配合使用. Raycast 和 Alfred 差不多,Raycast 我装了,但是用的频率不高,目前没发现他有什么特别的亮点,用来作为 Alfred 的备选,毕竟免费. Context有一个feature就是可以切换window,比如,AndroidStudio里打开了多个Project,形成了多个window,这说话,直接Alfred打开Androidstudio的话,只是打开了软件,至于哪个Window,有时候不清楚,这种情况下,Context 是个很好的补充. Context 的缺陷就是,他只是用来打开,已有的窗口的. 输入法 搜狗输入法 目前国内也就搜狗输入法还行了,当然百度也有Mac版本,但是体验上,还是搜狗好点. 终端 iterm2 oh-my-zsh Mac 下很好的终端工具了.目前没发现其他替代品; Git fork Native开发,相比对sourceTree,颜值和性能都更高,无他,颜值即正义. Android开发 AndroidStudio 开发Android必备,只是有一点至今让我诟病的地方,就是ActivityStack的打印被删除了… C/Cpp开发 Clion VSC配置cpp开发环境也试过,繁琐.Mac 下的Xcode也用过,感觉一般, 不得不说,jetbrains做的IDE,真香. Java开发 IntellijIdea Eclipse NetBeans 目前在用的就是 IntellijIdea 了,其他的基本不用了.只有一个 NetBeans 在某些场景下是有优势的,那就是JavaSE GUI开发的时候. 清除广告 AdBlock Pro 清除Safari广告用; 看动漫太多的广告了,Chrome 上清除广告很容易,Safari就只能依赖这个plugin了. database DataGrip 一个客户端,支持查看所有的数据库,jetbrains太香了. 分屏 Grid windows 系统有个自动管理窗口的功能,这个软件就是在Mac上实现类似的功能; 扩展屏幕 Deskreen 只要有个浏览器就可以实现屏幕的扩展,有时候可以将自己的iPad用上. statusbar 隐藏图标 Dozer Bartender

一张思维导图看 Java 【持续迭代】

概述 总结自己的 java 知识,按照编码 -> 运行,画了一张图,xmind 导出的图比较大,后续持续更新,迭代这部分的内容。 下面是一些常见的知识,将会慢慢补充进思维导图内 HashMap 原理 可参考的文章 HashMap原理,循环链表是如何产生的 HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你! 转换红黑树的阈值为何设置为8 官方comment 结构 Java 8 之前:数组 + 链表 Java 8 之后:数组 + 链表; 存储的对象 Java7 Entry<K,V>[] table,Entry 是 HashMap 中的一个静态内部类,它有key、value、next、hash(key的hashcode)成员变量。 Java8 TREEIFY_THRESHOLD 用于判断是否需要将链表转换为红黑树的阈值。 HashEntry 修改为 Node。 负载因子: 给定的默认容量为 16,负载因子为 0.75。Map 在使用过程中不断的往里面存放数据,当数量达到了 16 * 0.75 = 12 就需要将当前 16 的容量进行扩容,而扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。 因此通常建议能提前预估 HashMap 的大小最好,尽量的减少扩容带来的性能损耗。 put 操作 Java7 判断当前数组是否需要初始化。 如果 key 为空,则 put 一个空值进去。 根据 key 计算出 hashcode。 根据计算出的 hashcode 定位出所在桶。 如果桶是一个链表则需要遍历判断里面的 hashcode、key 是否和传入 key 相等,如果相等则进行覆盖,并返回原来的值。 如果桶是空的,说明当前位置没有数据存入,新增一个 Entry 对象写入当前位置。 当调用 addEntry 写入 Entry 时需要判断是否需要扩容。如果需要就进行两倍扩充,并将当前的 key 重新 hash 并定位。而在 createEntry 中会将当前位置的桶传入到新建的桶中,如果当前桶有值就会在位置形成链表。 Java8 当 Hash 冲突严重时,在桶上形成的链表会变的越来越长,这样在查询时的效率就会越来越低;时间复杂度为 O(N),因此 1.