mmap

mmap mmap 函数是 unix/linux 下的系统调用 mmap() 函数用来将文件或者设备映射到内存中。 mmap 的特点是按需调页。最开始只申请 vma(Virtual Memory Area),并不调真正的页。当对某些页进行引用的时候,会引起一个缺页中断,再将页面调入到内存当中,这样避免了对内存的浪费。 内存映射, 是将用户空间的一段内存区域映射到内核空间, 映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。 那么对于 内核空间 <—-> 用户空间 两者之间需要大量数据传输等操作的话效率是非常高的。 mmap 是一种内存映射文件的方法, 即将一个文件或者其它对象映射到进程的地址空间, 实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上, 即完成了对文件的操作而不必再调用 read, write 等系统调用。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享 mmap 优点 对文件的读取操作跨过了页缓存, 减少了数据的拷贝次数, 用内存读写取代I/O读写, 提高了文件读取效率。 实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内, 从而被对方空间及时捕捉。 提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动, 达到进程间通信和进程间共享的目的。 同时, 如果进程A和进程B都映射了区域C, 当A第一次读取C 时通过缺页从磁盘复制文件页到内存中;但当B 再读C 的相同页面时, 虽然也会产生缺页异常,但是不再需要从磁盘中复制文件过来, 而可直接使用已经保存在内存中的文件数据。 可用于实现高效的大规模数据传输。 内存空间不足,是制约大数据操作的一个方面,解决方案往往是借助硬盘空间协助操作,补充内存的不足。但是进一步会造成大量的文件I/O操作,极大影响效率。这个问题可以通过mmap映射很好的解决。换句话说,但凡是需要用磁盘空间代替内存的时候, mmap 都可以发挥其功效。 操作文件就像操作内存一样,适合于对较大文件的读写。 用户也可创建匿名内存映射, 该映射没有对应的文件, 可用于存放程序数据。在 Linux中,若通过 malloc()请求一大块内存,C 运行库将创建一个匿名内存映射,而不使用堆内存。“大块” 意味着比阈值 MMAP_THRESHOLD还大,缺省为128KB,可通过 mallopt()调整。 mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。 prot: 期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起 PROT_EXEC //页内容可以被执行 PROT_READ //页内容可以被读取 PROT_WRITE //页可以被写入 PROT_NONE //页不可访问 ...

2017-02-10 · 2 min · 270 words · -

开放地址法, Open Addressing

开放地址法, Open Addressing 本文我们来探讨一个数据结构的基础话题:hash 结构中的开放地址法(Open Addressing) HashMap 无 Java 人不知无 Java 人不晓,它使用开链法处理 hash 碰撞,将碰撞的元素用链表串起来挂在第一维数组上。但是并不是所有语言的字典都使用开链法搞定的,比如 Python,它使用的是另一种形式 —— 开放地址法。相比 HashMap 是二维的结构,它只是一维的,只有一个数组。 开放地址法与开链法的不同之处在于如何处理 hash 冲突。当新来一个元素哈希到数组中的位置已经被其它元素占据了该怎么办? 开放地址法会根据当前的位置计算出下一个位置,将这个冲突的元素挪进来。如果这下一个位置也被占用了,那么就再计算下一个位置,直到找到一个空的位置。可以想像,将会有一条虚拟的链条将这些相关的位置串起来。这个虚拟的链条就好比开链法里面的第二维链表。只不过链表有显示的指针字段,而虚拟链条没有,它的这个链条完全是通过数学函数计算出来的。 root = hash(key) % m // 第一个位置,m 为数组的长度 index_i = (root + p(key, i)) % m // 链条中的第 i 个位置 index_1 = (root + p(key, 1)) % m index_2 = (root + p(key, 2)) % m … 复制代码这个数学函数就是上面代码中的 p —— probe sequence (探测序列)。寻找空位置的过程就是一步一步的探测的过程。不同的 key 会生成不一样的探测序列。 在查找的时候,如果第一个位置上保存的 key 不是目标 key,那就沿着探测路径继续寻找,直到找到或者遇到一个空位置为止。 到这里你可能会担心又没有可能探测过程会出现死循环,探来探去又回到原点了,或者是回到路径的中间。这是很有可能的,所以这里的探测函数不能随意选择,它必须保证探测序列不会出现循环,经过 m-1 次探测生成的探测序列必须正好是 1..m-1的全排列。 这样的探测函数有很多,其中最常见的一种是线性探测函数。该探测序列和输入 key 无关。最终的探测路径只和初始位置相关。 // m = 2^n,c 必须是一个奇数 p(key, i) = c i index_i = root + c i 复制代码这里我不去仔细证明这个函数为什么满足要求,我们可以写个简单的代码来验证一下。 ...

2014-05-06 · 1 min · 188 words · -

accord, grant

accord, grant https://www.tjxz.cc/11067 give、accord、award、confer、grant、endow、present与bestow这组动词均含有“给予、赠给”之意。 give 最普通用词,泛指将自己的东西给予他人,所给予的东西,物质或非物质的均可。 She gave us a set of saucepans as a wedding present. 她送我的结婚礼物是一套深平底锅。 Can you give me a date for another appointment? 我能再和您约个时间吗? They never gave me a chance/choice. 他们从来就没给过我机会/选择余地。 Has the director given you permission to do that? 主任允许你那样做了吗? accord 侧重所给予的是应得的或是恰当的,或是因某种原因而适于接受的。 The massed crowds of supporters accorded him a hero’s welcome. 蜂拥云集的支持者们给予他英雄般的欢迎。 Certainly in our society teachers don’t enjoy the respect that is accorded to doctors and lawyers. 的确,在我们这个社会中,老师没有得到像医生和律师所受到的那种尊敬。 ...

2006-01-02 · 2 min · 230 words · -

apisix

“apisix” 启动etcd apisix podman run -d \ --name apisix \ -v apisix-logs:/usr/local/apisix/logs \ -v apisix-conf:/usr/local/apisix/conf \ -v /etc/letsencrypt/live/wiloon.com-0001:/usr/local/apisix/cert \ -p 9180:9180 \ -p 9080:9080 \ -p 443:9443 \ apache/apisix allow admin allow_admin: # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow - 192.168.50.116/24 # If we don’t set any IP list, then any IP access is allowed by default. 修改etcd 地址 etcd: host: - "http://192.168.50.101:2379" test curl "http://192.168.50.101:9080/apisix/admin/services/" -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' build apisix-dashboard buildah bud -f Dockerfile -t apisix-dashboard:1.5 . run apisix dashboard podman run -d \ --name apisix-dashboard \ -p 80:80 \ -v apisix-dashboard-config:/etc/nginx/conf.d/ \ -v /etc/localtime:/etc/localtime:ro \ nginx 设置 Upstream 创建 id 为 50 的上游信息 ...

2 min · 229 words · -

coupling relationship, 耦合关系

coupling relationship, 耦合关系 耦合 不同模块之间的关系就是耦合,根据耦合程度可以分为 7 种,耦合度依次变低。 内容耦合 公共耦合 外部耦合 控制耦合 标记耦合 数据耦合, Data Coupling 非直接耦合 内容耦合 内容耦合是最紧的耦合程度,一个模块直接访问另一模块的内容,则称这两个模块为内容耦合。 公共耦合 一组模块都访问同一个全局数据结构,则称之为公共耦合。 外部耦合 一组模块都访问同一全局简单变量,而且不通过参数表传递该全局变量的信息,则称之为外部耦合。外部耦合和公共耦合很像,区别就是一个是简单变量,一个是复杂数据结构。 控制耦合 模块之间传递的不是数据信息,而是控制信息例如标志、开关量等,一个模块控制了另一个模块的功能。 从控制耦合开始,模块的数据就放在自己内部了,不同模块之间通过接口互相调用。 标记耦合 调用模块和被调用模块之间传递数据结构而不是简单数据,同时也称作特征耦合。 数据耦合, Data Coupling 调用模块和被调用模块之间只传递简单的数据项参数。相当于高级语言中的值传递。 非直接耦合 两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。耦合度最弱,模块独立性最强。 子模块无需知道对方的存在,子模块之间的联系,全部变成子模块和主模块之间的联系。 内聚 偶然内聚 逻辑内聚 时间内聚 通信内聚 顺序内聚 功能内聚 https://yanhaijing.com/program/2016/09/01/about-coupling/

1 min · 42 words · -

dependency-library-service, 依赖 库, 服务

dependency-library-service, 依赖 库, 服务 依赖管理: 究竟该用库还是服务? https://www.zybuluo.com/sambodhi/note/642554 http://blog.jessitron.com/2017/01/dependencies.html 依赖管理:究竟该用库还是服务? 当一个系统变得越来越复杂的时候,它必然大量的依赖外部系统和内部其他系统的服务或者库才能达成业务目标,因此,这个时候,对依赖进行有效的管理才能提升业务故障容忍度,这也是大系统小做的核心思路。 在现实生活中,要创造一个没有任何外部依赖的应用并非不可能,但也是极具挑战的。这也是为什么依赖管理对于每个软件项目都是至关重要的一部分。 通常来说,软件中的依赖关系通常包括编译时依赖、测试时依赖和运行时依赖。而从依赖形式上可以分为库依赖和服务依赖。那么问题来了,依赖管理,究竟该用库还是服务的形式呢?如何取舍? Atomist的软件工程师Jessitron Kerr,日前写了一篇文章,阐述了她对依赖管理究竟用库还是服务的看法,分析了库和服务的对比、利弊、权衡等等方面,她的思路非常清晰,经作者Jessitron Kerr授权,InfoQ翻译并整理成本文,相信对各位读者有所帮助。 以下是正文。 依赖 依赖管理,没有人愿意去想这个问题。我们只是想让这些东西能够运行。它是软件中令人讨厌、悬而未决的问题之一。 每种语言系统都声称它们有包管理器和构建工具。这关系到依赖如何工作。有些系统确实做的比其他更好一些,但是没有一个是完整的。我们真的有点“一叶障目”。 依赖很重要。图像分析中的边界,边界总是罕有很多信息;但是比起图像中的节点,边界却容易被忽视。 依赖可以是相对显式的,比如在pom.xml或package.json中声明。它们可能很难发现,例如HTTP从配置、代码、输入构成的URL调用。 依赖描述了我们如何将事物联系在一起。这意味着,它们也决定我们如何选择分解。将事务分解是我们如何扩展软件系统:在我们自己头脑中调整,也就是说,根据复杂性做出调整,而非体积。 如果仔细看看依赖,希望它们不要再这么麻烦了,也许我们可以让它更接近正确。这个话题与本文相比,还有更多内容,但它只是一个开头。 库和服务的对比 两者最大的区别:定义。 库是编译的。它们在不同的存储库(或庞大的doom(也就是monorepo)库中的目录)中分为不同的模块,它们可能由不同的公司(至少是团队)维护。通过将相同的代码编译成多个应用程序(也称为服务)来实现代码复用。 作者在此处讨论的是编译范围(compile-scope)库。至于Provided-scope,以及像.dll(姑且这么称呼)是另外一个事物,应该可能是单独的类别,但本文不讨论这些。 服务:一个应用通过网络(或者通过同一台机器上的通信接口)调用另一个应用;代码在不同进程中运行。在如何找到对方有些繁琐费时:服务发现完全是自己的事,使用DNS是最常见的解决方案。 权衡 能见度 库是显式声明的,尽管并不总是特地声明。有些东西实际上会将代码引入我的代码中,无论是作为jar还是显式地作为代码。 如果有的话,服务依赖被非正式地声明。它们可能在日志记录中被发现。如果您选择允许哪些应用访问其他应用,则可能会从安全日志中看到它们。 部署 在我看来,这个差异很重要。 库:你可以发布它要求人们升级。如果你的库是内部的,你甚至可以升级其他团队的代码中的库版本。但是,只有用户能够决定何时正式应用这个新版本。当用户选择部署升级代码时,你的新代码才会随之升级。 服务:何时升级由你决定。你将旧代码转为新代码来部署,就这样。每个使用你的服务的人,都会随时使用新代码。就这样,突然间你有了这个权利。这也意味着,你可以选择一次性运行多少服务。这点是人们感到兴奋的独立可扩展性。 如果你的库或者服务有数据支撑,那么控制代码部署意味着数据格式有很多。如果数据库仅由服务来访问,那么可以将任何必要的翻译到代码中去。如果数据库被其他人合并的库访问,那么最好保持模式兼容。 版本控制 Rich Hickey曾经说过关于库的版本控制,其中大部分,也适用于服务。这里是我的笔记。 如果将接口更改为库,那么你就拥有了不同的库。如果你为它用同一个名称,并称为新版本,那么就有了一个不同的库,它拒绝与同一个库一起编译,并为阻碍大打出手。然后你就遇到版本冲突的问题。不同的语言系统的解决方式不同。当应用声明对两个库的依赖时,会发生版本冲突,每个库都声明对同名第四个库的依赖。在JavaScript中,无论如何,我们都可以在两者中编译,它不过是代码复制。而在Java中,你很可能在给定的ClassLoader中每个类名只有一个定义,所以工具选择最新版本,希望每个人都能应付。 服务,你可以弄得很复杂,做成某种版本的路由选择;也可以在生产中,同时运行多个版本的服务。明白了吗?你将同一个服务成为两个版本,但实际上是两个不同的服务,与库相同。或者,你可以在在统一代码中支持API的多个版本。向后兼容性,是你和所有实际可工作软件的痛点。 API更改和向后兼容性 因此,你要改变用户和你的代码的交互方式。这里有一个很重要的区别:更改代码(重构、错误修复、完全重写)与要求客户为正确应用更改代码而更改是非常不同的,这是一个严重的影响。 服务:谁使用它?也许它是一个内部服务,你有通过grep来查看所有公司代码中使用你的URL的念头,对吧?你可以选择与这些团队来更改你的服务的使用。或者采取面向公众的服务。不要改变。你永远不知道谁在使用它。这确实令人沮丧。否则,你需要永久的向后兼容性。没错,你的代码将会变得令人厌恶。 库:如果你的包管理器相当好(意即不可变,如果它提供了某种库的版本,就永远将继续提供相同的下载),那么,旧版本的库仍然存在,他们可以留在生产环境中使用。你不能取消这个代码。但是,你可以令那些对版本号没有明确具体的用户心碎。这就是语义版本控制的所在。除了主版本的API的任何改变是鲁莽的,人们应该谨慎使用库的新的主版本。但如果你很友善,为它们取不同的名字,而不是假装同一个东西的不同版本号。 隔离 关于库的一个窍门:很难知道“什么是API更改?” 有了服务,事情就变得明了了:我们辨别出某些请求,并提供某种回应。 而使用库,就意味着所用的都是公用方法和公共类还有包……嗯,就像Java/Scala编码器那样,我甚至都没有特别注意我是否公开了。但是库的作者需要的话,他们会安全地变更库的内容。 服务是隔离的:你不能依赖我内部,因为你主体无法访问它们。为了显示出任何外部使用,我必须作出明确的决定。这是更为强大的模块化。这也意味着你可以用不同的语言来写它们。这是一个优势。 有几家公司在销售库。那些都是严肃的专业人士。他们必须从历史版本开始测试,在每个操作系统确保它们可以运行。他们必须清楚意识到暴露了什么,还要在很多情况下测试新版本。将它们扔在那里实用得多:即时向后兼容性是一个巨大的痛苦,但至少你知道它在哪里。 失败 库:一旦它失败,你的代码就会随之失败。它耗尽内存、进程中断。故障被同步传送,如果它失败,应用会感知到。 服务:如果它失效,或者没有回应,你真的不会知道它已经失效了。部分故障、不确定的故障,查找出来很难。就算在通过套接字协调的同一台机器上,也不能保证响应时间,或者响应是否传递。这是所有的使用这种模块化机制的主要代价。 结论 我认为选择是使用库还是服务来分配工作/模块化的最大考虑是选择哪种以及决定什么时候部署。谁在给定时间在生产环境中控制那些代码。 库更高效,更容易处理故障。这是一个事物。进程间通信更快,故障更容易处理,并且有可能达到一致性。 实际上,服务是去耦的。让一个团队负责自己的软件,编写并运营它。让团队于给定时间在生产中进行选择:这意味着不断变化的数据源或模式的希望。一般来说,我认为,由于在数据中存在的惯性,数据有很大的价值。在讨论软件架构时,重视不够。如果你有可靠的服务接口来保护你的数据访问,你可以(与棘手的工作)将其移动到不同的数据库或格式。否则,数据迁移就无从谈起。 随着组织的日益壮大,部署时解耦对于保持发展的势头至关重要。功能和语言系统的解耦、版本、工具都有所帮助。要求每个人都使用相同的工具(或但愿不会如此,存储库)是以可避免的方式将每个团队耦合到另一个团队。 总体来说,库更快,直到协调成为瓶颈。而服务能打开更多的瓶颈,它会使你的瓶颈更为难以理解。 其实依赖管理还有很多问题。本文探讨的是依赖管理部分的重要一点。基于实际情况做出何种选择都是可行的。选择好了之后,要“含泪保持微笑”地钻研。 Dependencies Dependency management. Nobody wants to think about it. We just want this stuff to work. It is one of the nasty sneaky unsolved problems in software. ...

8 min · 1688 words · -

embedded basic

“embedded basic” MCU 微控制单元MCU (Microcontroller Unit) 又叫单片机、微处理器,是集成电路的一种。MCU类似于CPU,是可以执行嵌入式程序的一种集成电路。 MCU执行的程序叫嵌入式程序。嵌入式程序可以存储在MCU上,也可以存储在外面的存储器上。比如Flash就是存储器的一种。 模组: 芯片必须配合一些外围设备才能工作。为了方便厂家使用,模组厂家会集成一些外围部件,并写入嵌入式程序,整体打包后作为一个解决方案,给设备厂家使用。 MCU可以算是CPU+RAM+ROM+UART+TIMER+RTC等简单外设。 SoC (System on Chip) ,中文名是片上系统。SoC含义很多,有一种定义是一个有专用目标的集成电路,是一个包含嵌入式软件的完整系统。SoC方案中,对设备所有智能化操作都是通过模组来实现的,设备无需另外增加MCU。此类控制通常而言比较简单,例如开关,灯之类的产品,只需要几个IO口,就可以控制产品。 JTAG JTAG (Joint Test Action Group,联合测试行动小组) 是一种国际标准测试协议 (IEEE 1149.1兼容) ,主要用于芯片内部测试。现在多数的高级器件都支持JTAG协议,如ARM、DSP、FPGA器件等。标准的JTAG接口是4线: TMS、 TCK、TDI、TDO,分别为模式选择、时钟、数据输入和数据输出线。 相关JTAG引脚的定义为: TMS: 测试模式选择,TMS用来设置JTAG接口处于某种特定的测试模式; TCK: 测试时钟输入; TDI: 测试数据输入,数据通过TDI引脚输入JTAG接口; TDO: 测试数据输出,数据通过TDO引 脚从JTAG接口输出; SWD接口 串行调试 (Serial Wire Debug) ,应该可以算是一种和JTAG不同的调试模式,使用的调试协议也应该不一样,所以最直接的体现在调试接口上,与JTAG的20个引脚相比,SWD只需要4个 (或者5个) 引脚,结构简单,但是使用范围没有JTAG广泛,主流调试器上也是后来才加的SWD调试模式。 SWD和传统的调试方式区别: SWD模式比JTAG在高速模式下面更加可靠。在大数据量的情况下面JTAG下载程序会失败,但是SWD发生的几率会小很多。基本使用JTAG仿真模式的情况下是可以直接使用SWD模式的,只要你的仿真器支持,所以推荐大家使用这个模式。 在大家GPIO刚好缺一个的时候,可以使用SWD仿真,这种模式支持更少的引脚。 在大家板子的体积有限的时候推荐使用SWD模式,它需要的引脚少,当然需要的PCB空间就小啦!比如你可以选择一个很小的2.54间距的5芯端子做仿真接口。 RDI 接口 远程调试接口 (Remote Debug Interface) ,是ARM公司提出的标准调试接口,主要用于ARM芯片的仿真,由于各个IDE厂商使用的调试接口各自独立,硬件无法进行跨平台的调试。现在众多的IDE厂家都逐步采用标准RDI作为ARM仿真器的调试接口,因此使跨平台的硬件调试成为可能。EasyJTAG由于使用标准RDI调试接口,因此在任何使用标准RDI接口的IDE调试环境中都可以使用,例如ARM公司的ADS1.2/IAR公司的EWARM 3.30 。 J-Link J-Link是最著名的ARM开发调试工具,J-Link由SEGGER公司生产。提供对市面上几乎所有ARM内核芯片的支持。目前最新版本的J-Link产品为V8,支持JTAG和SWD模式。并且对主要的IDE环境如KEIL、IAR都有良好的支持。优点很多,因此也是首选的调试工具。 所以JLINK就是怎么个作用呢? 起到一个中间转换桥梁,芯片测试用的是JTAG,而JTAG另一端在早起是并口,而现在大多都是USB口,中间过度的重担就交给了Jlink。 ULink仿真器 ULINK是ARM/KEIL公司推出的仿真器,目前网上可找到的是其升级版本,ULINK2和ULINK Pro仿真器。ULINK/ULINK2可以配合Keil软件实现仿真功能,并且仅可以在Keil软件上使用,增加了串行调试 (SWD) 支持,返回时钟支持和实时代理等功能。开发工程师通过结合使用RealView MDK的调试器和ULINK2,可以方便的在目标硬件上进行片上调试 (使用on-chip JTAG,SWD和OCDS) 、Flash编程。 ...

2 min · 337 words · -

equipment, device

“equipment, device” equipment “Equipment” 通常指 “成套的,不只一件的设备”。而且,与 “device” 和 “appliance” 不同的是,“equipment” 不光包括 “电子设备”,还包含相关的工具。比如,上文提到的 “cycling and diving equipment 自行车和潜水装备” 中可能包括服装、自行车灯、潜水眼镜、呼吸器等物品;再如,“医疗设备” 的说法是 “medical equipment”。比如,虽然 “听诊器 stethoscope” 是一种 “medical equipment”,但它并不是一个 “medical device”,因为听诊器不是电子的。 device device" 通常指 “小巧的电子装置或设备”,比如 “移动设备 mobile device”、“听力装置 listening device”。“Device” 是可数名词。来听一个例句。

1 min · 38 words · -

esp,ebp,栈指针,帧指针

“esp,ebp,栈指针,帧指针” (1) ESP: 栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。 (2) EBP: 基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。 栈帧每一个都对应一个过程,而且每一个帧指针+4的位置都存储着函数的返回地址,每一个帧指针指向的存储器位置当中都备份着调用者的帧指针。各位需要知道的是,每一个栈帧都建立在调用者的下方 (也就是地址递减的方向) ,当被调用者执行完毕时,这一段栈帧会被释放。还有一点很重要的是,%ebp和%esp的值指示着栈帧的两端,而栈指针会在运行时移动,所以大部分时候,在访问存储器的时候会基于帧指针访问,因为在一直移动的栈指针无法根据偏移量准确的定位一个存储器位置。 还有一点比较重要的内容,就是栈帧当中内存的分配和释放。由于栈帧是向地址递减的方向延伸,因此如果我们将栈指针减去一定的值,就相当于给栈帧分配了一定空间的内存。这个理解起来很简单,因为在栈指针向下移动以后 (也就是变小了) ,帧指针和栈指针中间的区域会变长,这就是给栈帧分配了更多的内存。相反,如果将栈指针加上一定的值,也就是向上移动,那么就相当于压缩了栈帧的长度,也就是说内存被释放了。需要注意的是,上面的一切内容,都基于一个前提,那就是帧指针在过程调用当中是不会移动的。 函数调用的故事 调用者的各种参数入栈 调用者的返回地址入栈,这个是用 前指令地址++ 作返回地址的 调用者的帧指针入栈保护 (本次调用的基址指针就指向这里) 调用者的寄存器入栈保护 被调用的函数的局部变量的分配 https://blog.csdn.net/u011822516/article/details/20001765 https://www.tenouk.com/Bufferoverflowc/Bufferoverflow2a.html https://zhuanlan.zhihu.com/p/37537046

1 min · 29 words · -

etcd

“etcd” etcd etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法, etcd基于Go语言实现。 本文的主角是 etcd。名称 “etcd” 源自两个想法,即 unix “/etc” 文件夹 和 “d” 分布式系统。“/etc” 文件夹是用于存储单个系统的配置数据的位置,而 etcd 用于存储大规模分布式的配置信息。因此,分配了 “d” 的 “/etc” 就是 “etcd”。 etcd 被设计为大型分布式系统的通用基板。这些大型系统需要避免裂脑操作,并且愿意牺牲可用性来实现此目的。 etcd 以一致且容错的方式存储元数据。 etcd 集群旨在提供具有稳定性、可靠性、可伸缩性和性能的键值存储。 分布式系统将 etcd 用作配置管理、服务发现和协调分布式工作的一致键值存储组件。许多组织在生产系统上使用 etcd,例如容器调度程序、 服务发现服务和分布式数据存储。使用 etcd 的常见分布式模式包括领导者选举、分布式锁和监视机器活动状态等。 此外,etcd 开箱即用地支持多种语言和框架。Zookeeper 拥有自己的自定义Jute RPC 协议,该协议对于 Zookeeper 而言是完全唯一的,并限制了其受支持的语言绑定,而 etcd 的客户端协议则是基于 gRPC 构建的,gRP 是一种流行的 RPC 框架,具有 go,C ++,Java 等语言支持。同样,gRPC 可以通过 HTTP 序列化为 JSON,因此即使是通用命令行实用程序 (例如curl) 也可以与之通信。由于系统可以从多种选择中进行选择,因此它们是基于具有本机工具的 etcd 构建的,而不是基于一组固定的技术围绕 etcd 构建的。 在考虑功能,支持和稳定性时,etcd 相比于 Zookeeper,更加适合用作一致性的键值存储的组件。 etcd的特点 简单: 安装配置简单,而且提供了HTTP API进行交互,使用也很简单 安全: 支持SSL证书验证 快速: 根据官方提供的benchmark数据,单实例支持每秒2k+读操作 可靠: 采用raft算法,实现分布式系统数据的可用性和一致性 概念术语 Raft: etcd 所采用的保证分布式系统强一致性的算法。 Node: 一个Raft状态机实例。 Member: 一个etcd实例。它管理着一个Node,并且可以为客户端请求提供服务。 Cluster: 由多个Member构成可以协同工作的etcd集群。 Peer: 对同一个etcd集群中另外一个Member的称呼。 Client: 向etcd集群发送HTTP请求的客户端。 WAL: 预写式日志,etcd用于持久化存储的日志格式。 snapshot: etcd防止WAL文件过多而设置的快照,存储etcd数据状态。 Proxy: etcd的一种模式,为etcd集群提供反向代理服务。 Leader: Raft算法中通过竞选而产生的处理所有数据提交的节点。 Follower: 竞选失败的节点作为Raft中的从属节点,为算法提供强一致性保证。 Candidate: 当Follower超过一定时间接收不到Leader的心跳时转变为Candidate开始竞选。 Term: 某个节点成为Leader到下一次竞选时间,称为一个Term。 Index: 数据项编号。Raft中通过Term和Index来定位数据。 数据读写顺序 为了保证数据的强一致性,etcd集群中所有的数据流向都是一个方向,从 Leader (主节点) 流向 Follower,也就是所有 Follower 的数据必须与 Leader 保持一致,如果不一致会被覆盖。 ...

2 min · 337 words · -

etcd basic

“etcd basic” 单节点的etcd podman run -d \ -p 2379:2379 \ -v etcd-data:/etcd-data \ --add-host=localhost:127.0.0.1 \ -e ETCD_DATA_DIR="/etcd-data" \ -e ETCD_ENABLE_V2="true" \ -e ALLOW_NONE_AUTHENTICATION="yes" \ -e ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379" \ -e ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" \ --name etcd bitnami/etcd:latest set, get etcdctl ls etcdctl set /testdir/testkey "foo" etcdctl get /testdir/testkey etcdctl update /testdir/testkey "Hello" etcdctl rm /testdir/testkey etcdctl mk /testdir/testkey "Hello world" etcdctl mkdir testdir2 https://etcd.io/docs/v3.4.0/op-guide/container/ https://github.com/etcd-io/etcd/blob/master/Documentation/op-guide/container.md

1 min · 61 words · -

flutter

“flutter” install yay -S flutter flutter doctor https://flutter.dev/docs/get-started/install/linux https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_2.0.5-stable.tar.xz export export FLUTTER_STORAGE_BASE_URL=“https://mirrors.tuna.tsinghua.edu.cn/flutter" export PUB_HOSTED_URL=“https://mirrors.tuna.tsinghua.edu.cn/dart-pub"

1 min · 14 words · -

github action

“github action” Deploy to vm - name: Deploy to vm uses: easingthemes/ssh-deploy@v2.1.2 env: SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} ARGS: "-avz --delete" SOURCE: "public/" REMOTE_HOST: "192.168.0.xxx" REMOTE_PORT: 38785 REMOTE_USER: "blog" TARGET: "/home/blog/public/" secrets.SSH_PRIVATE_KEY 粘贴私钥时后面加一个换行,否则会报错,invalid format

1 min · 33 words · -

golang sync.Map

“golang sync.Map” func main() { m := sync.Map{} m.Store(1,1) go do(m) go do(m) time.Sleep(1*time.Second) fmt.Println(m.Load(1)) } func do (m sync.Map) { i := 0 for i < 10000 { m.Store(1,1) i++ } } 清空 sync.Map https://stackoverflow.com/questions/49355345/how-to-clean-a-sync-map //erase map: A zero sync.Map is empty and ready for use. map2 = sync.Map{} 在Go 1.6 之前, 内置的 map 类型是部分 goroutine 安全的, 并发的读没有问题, 并发的写可能有问题。自 go 1.6之后, 并发地读写 map 会报错, 这在一些知名的开源库中都存在这个问题, 所以go 1.9之前的解决方案是额外绑定一个锁, 封装成一个新的struct或者单独使用锁都可以。 ...

5 min · 908 words · -

golang的类型转换, 强转、断言、“向上造型“

“golang 的类型转换, 强转、断言、“向上造型“” Golang的类型转换-三种转型(强转、断言、“向上造型“) 无数_mirage 2021-02-04 16:05:12 216 收藏 文章标签: golang go 接口 版权 golang没有类似于java中的隐式类型转换 golang中的类型转换分为强制类型转换、类型断言、以及“向上造型” 向上造型这个词是取的Java中的定义,没有复杂的含义,表示将子类转为父类。在golang中达到同样的目的只需要.父结构体即可 package main import “fmt” // 隐式类型转换和强转 func t1(){ var a float32 = 5.6 var b int = 10 //fmt.Println (a * b) // – 隐式类型转换,编译报错,不支持 fmt.Println(a * float32(b)) // – 强转 } type Base interface { hello() } type P interface { hi() } type S1 struct { } func (s1 *S1) hi() { fmt.Println(“s1-hi”) } func (s1 *S1) hello() { fmt.Println(“s1-hello”) } type S2 struct { } ...

1 min · 176 words · -

hugo, envoy, github actions

“hugo, envoy, github actions” install sudo pacman -S hugo hugo new site quickstart cd quickstart git init git submodule add https://github.com/theNewDynamic/gohugo-theme-ananke.git themes/ananke echo theme = \"ananke\" >> config.toml hugo new posts/my-first-post.md hugo server -D hugo new site wiloon.com cd wiloon.com git init git clone https://github.com/olOwOlo/hugo-theme-even themes/even cp themes/even/exampleSite/config.toml config.toml hugo new post/my-first-post.md hugo server -D hugo pages, nginx server simple podman run -d \ --name hugo \ -p 30080:80 \ -v /home/blog/public:/usr/share/nginx/html \ -v /etc/localtime:/etc/localtime \ nginx:alpine hugo pages, nginx server podman run -d \ --name hugo \ --ip=10.88.0.10 \ -v /home/blog/public:/usr/share/nginx/html \ -v /etc/localtime:/etc/localtime \ nginx:alpine hugo-envoy podman run -d \ --name hugo-envoy \ -v /opt/hugo/service-envoy.yaml:/etc/envoy/envoy.yaml \ -v /etc/localtime:/etc/localtime \ --net=container:hugo \ envoyproxy/envoy-alpine:v1.14.1 front-envoy podman run -d \ --name front-envoy \ --add-host=hugo:10.88.0.10 \ -v /opt/hugo/front-envoy.yaml:/etc/envoy/envoy.yaml \ -v /etc/localtime:/etc/localtime \ -v /root/.acme.sh/yangcs.net:/root/.acme.sh/yangcs.net \ --net host \ envoyproxy/envoy-alpine:v1.14.1 https://blog.humblepg.com/post/2020/02/log-hugo-github-actions.html ...

2 min · 328 words · -

icebox

“icebox” 先用adb安装 谷歌版冰箱激活 Root方法: 把冰箱apk放到 /data/local/tmp/ 文件夹中,然后为方便起见重命名为icebox.apk 然后打开终端,su后输入 pm install -i “com.android.vending” -r /data/local/tmp/icebox.apk 搞定[受虐滑稽] adb方法: 手机接上电脑, 执行 adb push [冰箱apk位置] /data/local/tmp/icebox.apk adb shell pm install -i “com.android.vending” -r /data/local/tmp/icebox.apk adb shell rm /data/local/tmp/icebox.apk 同样搞定[受虐滑稽][受虐滑稽] 然后你就可以连上谷歌验证购买了 参考: https://medium.com/@pixplicity/setting-the-install-vendor-of-an-app-7d7deacb01ee 冰箱免 Root (设备管理员模式) 手动配置 https://github.com/heruoxin/Ice-Box-Docs/blob/master/Device%20Owner%20%EF%BC%88%E5%85%8D%20root%EF%BC%89%E6%A8%A1%E5%BC%8F%E8%AE%BE%E7%BD%AE.md adb shell dpm set-device-owner com.catchingnow.icebox/.receiver.DPMReceiver

1 min · 48 words · -

Infinitive 不定式

Infinitive 不定式 动词不定式一般是由“to + 动词原形”构成,还需要注意得是,这里的 to 是动词不定式的一部分,不做介词使用。举几个动词不定式的例子: to be to have to hold to sleep to spend 一定要注意的是,动词不定式中词尾从不以-ed或-ing结尾。动词不定式是动词的三种类型之一,具有动词、形容词、名词或副词的特征。在句子中通常可以作主语、宾语、补语、表语、定语、状语等。 https://liulingo.com/infinitive-yong-fa-he-li-zi

1 min · 19 words · -

java coroutine

“java coroutine” Kotlin https://github.com/puniverse/quasar https://github.com/offbynull/coroutines https://github.com/kilim/kilim

1 min · 6 words · -

java 替换 ascii 不可见字符, StringEscapeUtils.escapeJava

“java 替换ascii不可见字符, StringEscapeUtils.escapeJava” StringEscapeUtils.escapeJava StringEscapeUtils.escapeJava String.replaceAll 替换成? my_string.replaceAll("\\p{C}", "?"); https://stackoverflow.com/questions/6198986/how-can-i-replace-non-printable-unicode-characters-in-java StringEscapeUtils 在java.commons.lang3的包中有许多方便好用的工具类,类似于处理字符串的StringUtils,处理日期的DateUtils等等,StringEscapeUtils也是其中的一员。 StringEscapeUtils是在java.commons.lang3的2.0版本中加入的工具类,在3.6版本中被标注为@deprecated,表明在之后的版本中则为过时状态,之后StringEscapeUtils类被移到java.commons.text包下。 功能用途 StringEscapeUtils的主要功能就是为Java,Java Script,Html,XML进行转义与反转义。 escapeJava(String input) / unescapeJava(String unionCodeString) 将输入字符串转为unicode编码 / 将unicode字符串转为Utf-8格式的字符串 escapeHtml4(String input) / unescapeHtml4(String input) 转义/反转义html脚本 escapeEcmaScript(String input) / unescapeEcmaScript(String input) 转义/反转义js脚本 escapeXml(String input) / unescapeXml(String input) 转义/反转义xml脚本 除了列出的几个较常用的方法,还有escapeJson(String input) / unescapeJson(String input)、escapeCsv(String input) / unescapeCsv(String input)等等,可以看一下下面的执行例子,有个直观的认识。 import org.apache.commons.text.StringEscapeUtils; import org.junit.Test; /** * @author liuqian * @date 2018/4/3 16:27 */ public class EscapeTest { @Test public void escapeTest() { System.out.println("转义/反转义Java字符串"); String javaString = "这是Java字符串"; System.out.println(StringEscapeUtils.escapeJava(javaString)); System.out.println(StringEscapeUtils.unescapeJava(StringEscapeUtils.escapeJava(javaString))); System.out.println("-------------------------------------------------------------"); System.out.println("转义/反转义Json字符串"); String jsonString = "{\"keyword\": \"这是Json字符串\"}"; System.out.println(StringEscapeUtils.escapeJson(jsonString)); System.out.println(StringEscapeUtils.unescapeJson(StringEscapeUtils.escapeJson(jsonString))); System.out.println("-------------------------------------------------------------"); //除了html4还有html3等格式 System.out.println("转义/反转义Html字符串"); String htmlString = "加粗字符"; System.out.println(StringEscapeUtils.escapeHtml4(htmlString)); System.out.println(StringEscapeUtils.unescapeHtml4(StringEscapeUtils.escapeHtml4(htmlString))); System.out.println("-------------------------------------------------------------"); //除了xml10还有xml11等格式 System.out.println("转义/反转义xml字符串"); String xmlString = "<xml>\"xml字符串\"</xml>"; System.out.println(StringEscapeUtils.escapeXml10(xmlString)); System.out.println(StringEscapeUtils.unescapeXml(StringEscapeUtils.escapeXml10(xmlString))); System.out.println("-------------------------------------------------------------"); System.out.println("转义/反转义csv字符串"); String csvString = "1997,Ford,E350,\"Super, luxurious truck\""; System.out.println(StringEscapeUtils.escapeCsv(csvString)); System.out.println(StringEscapeUtils.unescapeCsv(StringEscapeUtils.escapeCsv(csvString))); System.out.println("-------------------------------------------------------------"); System.out.println("转义/反转义Java Script字符串"); String jsString = "<script>alert('1111')</script>"; System.out.println(StringEscapeUtils.escapeEcmaScript(jsString)); System.out.println(StringEscapeUtils.unescapeEcmaScript(StringEscapeUtils.escapeEcmaScript(jsString))); } } 结果 转义/反转义Java字符串 \u8FD9\u662FJava\u5B57\u7B26\u4E32 这是Java字符串 ------------------------------------------------------------- 转义/反转义Json字符串 {\"keyword\": \"\u8FD9\u662FJson\u5B57\u7B26\u4E32\"} {\"keyword\": \"这是Json字符串\"} ------------------------------------------------------------- 转义/反转义Html字符串 <strong>加粗字符</strong> 加粗字符 ------------------------------------------------------------- 转义/反转义xml字符串 <xml>&quot;xml字符串&quot;</xml> <xml>"xml字符串"</xml> ------------------------------------------------------------- 转义/反转义csv字符串 "1997,Ford,E350,""Super, luxurious truck""" 1997,Ford,E350,"Super, luxurious truck" ------------------------------------------------------------- 转义/反转义Java Script字符串 <script>alert(\'1111\')<\/script> <script>alert('1111')</script> https://github.com/lq920320/blogs/issues/9

1 min · 160 words · -