当前位置: 首页 > news >正文

企业园林设计网站模板怎么向国外打广告

企业园林设计网站模板,怎么向国外打广告,WordPress部署百度广告,图片制作用什么软件一、背景 这篇博客#xff0c;我们继续之前的 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 博客里对初始化分配逻辑进行分析#xff0c;已经涉及到了jemalloc 5.3.0里的非常重要的base模块的一部分逻辑#xff…一、背景 这篇博客我们继续之前的 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 博客里对初始化分配逻辑进行分析已经涉及到了jemalloc 5.3.0里的非常重要的base模块的一部分逻辑在这篇博客里我们进一步展开分析base模块针对的场景也依然是初始化分配逻辑这块来作为切入口。 在第二章里我们先顺着之前的博客 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 里 3.2.4 里重点提到的malloc_init_hard函数继续展开分析在 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 博客里我们分析了初始化逻辑里的tsd模块的初始化逻辑在 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 博客里我们讲到了几个关键概念group、delta、class还有sz.h里几个常用的pszsizeindex之间的转换函数及相关含义有了这两篇的基础base模块的详细分析相对容易一些。 我们在第二章我们依然以malloc_init_hard里内存分配逻辑作为切入口来展开详细分析base模块对于相关联的概念也会一一进行介绍在第三章里我们会用思维导图来汇总一下并附上总结说明。 二、依然以malloc_init_hard里的内存分配逻辑作为切入口展开详细分析base模块 2.1 base_boot里的2M的分配用的是base_block_alloc函数是base模块的分配函数 jemalloc 5.3.0的第一次内存分配的地方就是这个malloc_init_hard_a0_locked里的base_boot函数最终调用的base_map进行的2M的分配。 这块我们在之前的博客 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 里已经做了一些介绍这篇博客里需要再展开分析一下。 base_boot有关的调用链是 malloc_init_hard-malloc_init_hard_a0_locked-base_boot-base_new-base_block_alloc-base_map  我们先说一下base模块是什么用来干什么 2.2 base模块是一个metadata数据的一个分配器 base模块的文件就两个base.h和base.c。 base模块是一个metadata数据的一个分配器。那么什么是metadata数据呢metadata就是元数据也就是数据的数据。 base模块只分配元数据的内存而并不分配malloc的客户所要的内存也就是说malloc的使用者所要的内存是由jemalloc里的base分配器以外的其他的底层内存分配器来分配的这一点我们下面会用堆栈截图来证明。 2.2.1 三个用于分配的base接口都可能会调用到base_block_alloc函数 base模块用于分配的主要接口是三个base_new函数和base_alloc和base_alloc_edata其中base_alloc和base_alloc_edata函数其中base_new用于base的初始化base本身也是一个元数据另外两个则是在指定的base里分配元数据当然虽然说在指定的base里分配但是还是可能按需扩容的并不是说base_new分配出内存了以后base_alloc和base_alloc_edata就不会分配新的内存了关于非base分配器来分配出来的调用链例子在下面 2.4 一节里会讲到。这三个函数在需要分配新的内存时都会调用base_block_alloc函数这个函数我们会在后面详细展开描述。 下图是base_new函数调用base_block_alloc函数的截图 base_alloc和base_alloc_edata这两个函数都会调用base_alloc_impl 而base_alloc_impl会在判断出当前空间不够时调用base_extent_alloc进行更多内存的分配 而base_extent_alloc就会调用base_block_alloc进行内存分配 2.2.2 分配元数据的base_alloc_edata接口相比base_alloc接口需要在base_alloc_impl时取回sn号设到base_alloc_edata接口返回的是edata_t指针里去 base_alloc和base_alloc_edata两个函数的主要区别在于base_alloc_edata需要在base_alloc_impl时取回sn号也就是序列号并设到新创建的edata_t这个元数据里。 这个sn号是base实例管理的在base结构初始化时设置成0 在base_new里创建完元数据后把上图里的extent_sn_next记录到了base实例里 base_new里调用base_block_alloc创建元数据时会把传入的表示sn号的指针指向的值加1 base_block_alloc里调用了base_edata_init函数 在base_edata_init函数里进行了1 你可能会问这个多出来的sn号有什么用在下面的 2.7.1 里会讲到。 2.3 base模块分配了哪些元数据 我们列一下base模块分配的元数据的种类列出的都是相对重要的元数据用一次调用栈例子来说明当然分配的同一种元数据对应的调用栈也可能是不一样的我们只是举其中的一次调用栈来说明。 2.3.1 base模块首先会分配base_t实例也就是base自己这个元数据 上图的堆栈是main之前的第一次malloc的调用这次malloc的调用我们在之前的博客 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 里也说明了是因为preload的jemalloc库时由于jemalloc的实现里包含了C的内容所以需要在main之前的初始化流程里做相关的C的异常处理用的pool的分配。而上图中的堆栈是由这一次分配触发判断出整个jemalloc还未进行初始化所以调用了malloc_init_hard接口关于malloc_init_hard接口我们之前的博客里 跟踪jemalloc 5.3.0的第一次malloc的源头原因及jemalloc相关初始化细节拓展-CSDN博客 的 3.2.4 分析过一部分这个函数会间接调用base_boot来初始化第一个base实例base_boot继而调用了base_newbase_new继而调用了base_block_alloc进行了分配base_block_alloc使用base_mapbase_map调用pages_map注意pages_map是base分配器以外的其他jemalloc内存分配器都会用到的一个接口定义在src/pages.c里它并不属于base模块。 看base_boot的返回类型就可以体现它分配的就是base_t这个元数据实例 0是第一个base第一个base由一个src/base.c里的上截图的static base_t *b0变量来保存的。 2.3.2 base模块会分配提供静态的tcache的tbins信息的cache_bin_info_t数组 cache_bin_info_t数组的首地址定义如下 它需要动态分配因为其大小不可静态确定。 相关的核心调用代码截图 可以看到上图里的这次分配大小不大就82字节n_reserved_bins是4141来自于nhbins因为nhbins比SC_NBINS的值大SC_NBINS是36 相关的上下文调用链如下 2.3.3 base模块会分配管理arena的arena_t的内存 arena是一个内存分配区不同的线程一般属于不同的arena默认情况下arena的个数是cpu核心数*4。 base模块分配arena实例的代码逻辑如下 如上图可以看到一个关于arena实例分配的细节 arena_t的大小是一个动态值因为arena_t用了柔性数组 相关base分配arena的调用链截图 要注意这次main之前的这个arena的分配由于分配的空间不大用之前base分配出来的内存池子里的剩余空间就足够了所以这次分配并没有触发base_map及底下分配接口。关于从base里挑选可用的空间来进行分配的逻辑见 2.7 一节。 2.3.4 base模块会分配用来管理实际使用数据内存块的edata_t管理结构 先说明一下edata它是管理的实际使用的数据内存块这么说edata还是一个元数据的数据结构它管理对应的内存分为两种一种是用户使用malloc接口触发进行分配的内存另一种是jemalloc实现的内部逻辑调用泛iallocztm或泛ipallocztm的接口进行内部使用的内存分配。 jemalloc对于不同大小的内存会有不同的策略对于小size的classjemalloc会预分配更多块这样的小块从而组成一个大块的内存块这个大块的内存块是page size的整数倍。当然对于大size的classjemalloc就不会预分配这样的内存块了。而edata_t就是管理这样的整块内存块的数据结构。 下图的场景仍然是main之前的在做初始化时的调用栈下图是在初始化tsd的tcache data的过程中分配各个size class的tcache_bin用的stack_head指针数组的内存时需要在具体分配该size的内存对应的内存块的分配前2.4.1 一节的截图流程先分配该size class的内存块对应的元数据edata数据结构。 上图里的base_alloc_edata所调用base_alloc_impl分配的大小是很小的如下图 就128字节 和 2.3.2 同样的由于分配的大小很小所以直接从base里的当前的block块里剩下的内存里扣出一块出来就可以了它并不会触发base_map及其他底层分配动作。 在启动过程中关于edata_t管理结构分配的另外一个场景是在tsd_tcache_data_init时在进行分配各个size class的tcache_bin用的stack_head指针数组的内存对应的内存块时发现通过ehooks_alloc分配出来的一大块extent内存块后有不用的多出来的部分这部分剩下的内存也需要创建对应的edata管理结构在创建该剩下的内存的edata管理结构时走到的edata_cache_get再到base_alloc_edata再到base_alloc_impl里而这个最后三级函数的调用是和刚才说的场景是一致的在extent_grow_retained函数内到最后三级函数edata_cache_get-base_alloc_edata-base_alloc_impl中间还有两级调用为extent_split_interior-extent_split_impl有关完整调用链可见第三章的调用链图。 2.3.5 base模块会分配用来管理关联每个edata信息所需要的radix tree所用到的叶子结构的内存 jemalloc里有个全局唯一的管理关联每个edata信息的radix tree即jemalloc里的rtree这个rtree需要用到rtree_leaf_elm_t结构所需要的该结构体的数量即radix tree的一层一层的数量这个数量是按照索引项的bit来决定的一层是18bit如下图 所以一层用到了11826144个如下图看到rtree_levels里就两层 这种情况所触发的函数如下图是在rtree_leaf_init函数里 调用链也是在初始化时场景 由于这次分配的大小较大 所以需要通过pages_map来向os要内存 上图里的pages_map实际做分配的size是在这次分配的调用链里是由base模块里的pind_last变量来管理维护的每次分配都要1因为1后得是HUGEPAGE_CEILING进行2M的对齐所以就变成了分配4M了有关pind_last的逻辑具体细节可参考之前的博客 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 里 2.2.5 一节。 2.3.6 base模块会分配background线程所用到的background_thread_info_t数据结构 相关的调用截图和调用链截图如下 2.4 非base分配器分配出内存的调用栈例子 这一节并不是本文的重点我们并不过多展开只是把相关调用栈贴出并描述相关调用场景。 这里说的其他分配器是指离调用os的mmap接口jemalloc默认只用mmap进行内存分配进行的内存分配非常近的调用层次的分配函数。jemalloc里pages_map接口封装了这样的os的mmap接口的内存分配作为一个接口给jemalloc里较底层的分配器所使用。所以无论是base分配器还是其他的下面会讲到的分配器最终还是会调用到pages_map接口。 2.4.1 使用extent_alloc_core分配函数 下图调用链是最终用到了extent_alloc_core函数而extent_alloc_core函数和base_map一样也是调用的extent_alloc_mmap函数下图调用链所在的场景是在初始化tsd的tcache data的过程中分配各个size class的tcache_bin用的stack_head指针数组的内存对应的内存块大小在对齐PAGE_SIZE后是32768字节 上截图也是在初始化流程中是在 2.3.4 截图流程之后在 2.3.5 截图的流程之前。 2.4.2 其他调用pages_map的分配器 调用extent_alloc_mmap进行分配的函数就base_map和 2.4.1 说的extent_alloc_core两个。 但是使用pages_map进行分配的函数还有一些如hpa模块 hpa_hooks模块 这里先不展开了。 2.5 base_block_alloc函数有点像分配一个内存池子每个base都至少有一个内存池子 我们回头来说base_block_alloc函数上面讲到base模块里的最终向操作系统去做分配的最终都汇总到了调用这个base_block_alloc函数里。 这个base_block_alloc函数有点像是预分配一个内存池。后面的大大小小的分配都需要在这个池子里进行再分配只是说这个内存池的管理是按照之前博客说的group delta这样管理的当然这个池子是可以变大的但是每一次变大的最小颗粒度很大之前的博客也说了是至少分配2M且一次分配比一次分配大参考之前的 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 博客里的 2.2.5 一节。 刚才说的这个内存池子的分配就是下图里的通过base_block_alloc函数得到的base_block_t 可以从下图中看到分配出来的block塞到了base_t结构体里的block链表里下图是因为是第一个block所以直接赋值就行了 如果是新增block则是下图里的红色框逻辑的逻辑目前新增block只会被base_extent_alloc函数用到 因为同一个base实例而言可以新关联base_block_t所以就有这一节标题里说的每个base都至少有一个内存池子意思就是可以有大于一个内存池子。 2.6 base_block_alloc函数分配出来的池子是对应base编号的且base编号是和arena的编号是一一对应的 1所谓的base_block_alloc函数分配出来的池子是对应base编号的意思就是base0至少有一个内存池子如果有base1的话那么base1也至少有一个内存池子如果一个base里发现内存不够可以新申请一个内存池子再与这个base关联。每笔使用base_block_alloc函数进行的内存分配都需要明确一个所属的base。 如下图传入给base_block_alloc函数的unsigned ind就是这个base编号 0是第一个base第一个base由一个base.c里的static base_t变量来保存是 2刚才说的base编号是和arena的编号一一对应的。下图是代码里能体现逻辑上arena的index对应于base的index的代码细节 3顺便提及一个arena的细节对于大size的内存分配jemalloc把它归到了最后一个index的arena里即如果cpu的数量是20大内存分配用的是最后一个arena即arena80假设arena0是第一个。 这块细节我们在以后的博客里会讲到。 2.7 base里挑选可用的空间来进行分配的逻辑 base里的这个挑选的逻辑就一处在base_alloc_impl里这个base_alloc_impl就是上面讲过的两个分配元数据的接口base_alloc和base_alloc_edata必经调用到的。 2.7.1 “挑选”逻辑用到了配对堆 Pairing Heap 在base_alloc_impl里有下面这段逻辑做所谓的“挑选” 上图里的红色框出的逻辑里核心函数edata_heap_remove_first是使用了配对堆的数据结构如下图看到base的avail数组就是配对堆的数据结构 base_alloc_impl的实现就是从base里的最多SC_NSIZES个配对堆里 从最小的可能满足size大小的配对堆往size更大的堆去找直到遇到非空的配对堆就返回堆里最小的元素。至于如何判断堆里元素谁大谁小见 2.7.3 一节。 我们先看一下配对堆的宏定义和使用。 2.7.2 配对堆的宏定义和使用 jemalloc里除了base模块里的内存管理以外数据内存块的管理者edata_cache模块和huge page的管理模块hpdata也使用到了配对堆所以配对堆的声明总共有3处两处在edata.h里另外一处在hpdata.h里 其中base模块用的是edata_heap。 配对堆的定义在各自的.c里如base模块用到的edata_heap是定义在edata.c里如下图显示了base模块用到的配对堆关联的配对函数edata_snad_comp 配对堆的一系列函数的函数名是由大量的宏拼接形成的如下 2.7.3 base用到的配对堆如何比较谁大谁小 我们看一下决定base模块用的配对堆里的元素决定谁大谁小的逻辑上一节也说到了该函数是edata_snad_comp 可以看到它是先比较edata的sn号关于edata的sn号我们在上面的 2.2.2 一节里说到了是如何生成的。 比较完sn号如果是一样的话再去比较地址大小。 这么比较是为了让早分配的内存更早被释放可以减少内存碎片。 2.7.4 base分配时选到的配对堆元素可能大于实际需要的大小相关的塞回配对堆的逻辑介绍 从上面的 2.7.1 一节里就可以看到base分配时选到的配对堆元素可能大于实际需要的大小。 我们看一下相关的塞回配对堆的逻辑在哪里base模块用的是base_extent_bump_alloc_post进行的塞回动作。 下图是base_extent_bump_alloc_post的选择塞哪里的逻辑 可以看到是用的floor也就是在塞的时候会塞到它实际所属的index的下一个这样在分配时拿到的元素肯定都能满足当前这个delta组里的所有size的情况。关于delta以及group等概念见之前的博客 由jemalloc 5.3.0初始化时的内存分配的分析引入jemalloc的三个关键概念及可借鉴的高性能编码技巧-CSDN博客 里的 2.2.4 一节。 三、malloc_init_hard时的所有内存分配动作的调用流程图 细心的同学会发现上面第二章里的所有截图出来的堆栈调用链都是在malloc_init_hard下的函数调用的。 我们把这个期间的所有的内存分配的逻辑调用都在上面一一列出来了进行了分析。 下面是一张整图如果需要再看得清楚一些可以参考我发布的资源里的图资源链接 https://download.csdn.net/download/weixin_42766184/90385037。
http://www.dnsts.com.cn/news/278314.html

相关文章:

  • html5网站建设威海网站建设价格
  • 北京住总第一开发建设有限公司网站首页带引导页的网站
  • 18芯城网站开发案例接入商网站备案
  • 徐州网站建设 网站制作html5网站带后台
  • 移动 开发 网站建设做问卷调查赚钱好的21个网站
  • 福永网站建设多少钱成都品牌网站建设
  • 网站备案年限杭州个人做网站
  • 海南做网站的公司有哪些阿里云空间做的网站不收录
  • not found的网站下载源代码的网站
  • 021新手学做网站网站后期维护费用怎样版费
  • 美空间网站网页视频怎么下载插件
  • 常见的网站名称有哪些建设一个网站需要学习什么
  • 简洁网站模板素材北京新闻最新消息
  • 自学python需要的软件wordpress主题 seo
  • 专门做手工的网站百度seo代理
  • 几个好用的在线网站2023年小微企业所得税
  • 做家常菜哪个网站最好广州微信网站建设平台
  • 微网站素材python基础教程学什么
  • 建设好一个网站需要站长工具2023最新国产
  • 在线网站备案项目建设的必要性
  • 无锡做网站优化哪家好wordpress cdn 非插件
  • 建设工程人才招聘信息网站在线制作图片书
  • 开发建设网站需要什么人才做网站需要ui设计吗
  • 织梦网站地图模板设计制作一个网站
  • 域名解析要登入哪个网站做怎样设计一个网站
  • 三河网站seo怎么自己电脑做网站服务器
  • 新开传奇手游网站大全营销培训课程有哪些
  • 运城做网站花垣县建设局网站
  • 企业购 网站建设动态交互图网站
  • 建设网站需要多久到账邯郸市内最新招聘信息