hi,大家好,今天分享一篇内存性能优化的文章,文章用了大量精美的图深入浅出地分析了Linux内核slab性能优化的核心思想,slab是Linux内核小对象内存分配最重要的算法,文章分析了内存分配的各种性能问题 (在不同的场景下面),并给出了这些问题的优化方案,这个对我们实现高性能内存池算法,或以后遇到内存性能问题的时候,有一定的启发,值得我们学习。 扩展到多核心CPU 现在我们简单的将上面的模型扩展到多核心CPU,同样差不多的分配序列如下图所示: 我们看到,在只有单一slab的时候,如果多个CPU同时分配对象,冲突是不可避免的,解决冲突的几乎是唯一的办法就是加锁排队 鉴于slab缓存对象大多数都是不超过1个页面的小结构(不仅仅slab系统,超过1个页面的内存需求相比1个页面的内存需求,很少),因此会有大量的针对1个页面的内存分配需求。 从伙伴系统的分配原理可知,如果持续大量分配单一页面,会有大量的order大于0的页面分裂成单一页面,在单核心CPU上,这不是问题,但是在多核心CPU上,由于每一个CPU都会进行此类分配,而伙伴系统的分裂
这两个目标就是衡量一个内存管理系统是否完善的标准,它是所有内存管理系统必须提供的基本抽象。 一、内存管理二三事 1.1 内存管理的目标 (1)地址保护:一个程序不能访问另一个程序地址空间。 在计算机中,体现在在内存容量不足时将不经常访问的内存空间中的数据写入硬盘,以增加“账面上”可用内存容量的手段(想想我们的内存和硬盘容量对比就知道了)。 虚拟内存的优点在于除了让程序员感觉到内存容量大大增加之外,还让程序员感觉到内存速度也增快了。 二、基本内存管理 2.1 单道编程的内存管理 在单道编程环境下,整个内存里面只有两个程序:一个是用户程序,另一个是操作系统。 但是,交换内存管理这种方式存在两个重要问题: (1)空间浪费:随着程序在内存与磁盘间的交换,内存将变得越来越碎片化,即内存将被不同程序分割成尺寸大小无法使用的小片空间。
个人网站、项目部署、开发环境、游戏服务器、图床、渲染训练等免费搭建教程,多款云服务器20元起。
缺点: (1)外部碎片和一个段必须全部加载到内存。 那么,解决办法是什么呢? 三、段页式内存管理 3.1 何为段页式内存管理 段页式管理就是将程序分为多个逻辑段,在每个段里面又进行分页,即将分段和分页组合起来使用。 四、内存管理的演变 (1)一开始,人们根据直觉,将一个程序作为一整段进行管理,从而形成了纯粹分段(固定加载地址、固定分区、非固定分区、交换)管理模式,也称为基本内存管理模式,这种模式由于直观易实现, (2)但是,纯粹分段存在重大缺陷(由于此种模式下一个程序只有一段,从而导致内存空间增长困难,外部碎片、程序不能超过物理内存容量、一个程序必须同时加载到内存才能执行等缺点),为了克服这些缺点,引入了页式内存管理模式 因此,内存管理模式经历了从纯粹分段到分页,再到逻辑分段,再到段内分页的演变过程,如下图所示: ? 参考资料 ?
分页系统的核心在于:将虚拟内存空间和物理内存空间皆划分为大小相同的页面,如4KB、8KB或16KB等,并以页面作为内存空间的最小分配单位,一个程序的一个页面可以存放在任意一个物理页面里。 (2)地址翻译:虚拟地址→物理地址 分页系统的核心是页面的翻译,即从虚拟页面到物理页面的映射(Mapping)。 缺页中断的处理步骤如下,省略了中间很多的步骤,只保留最核心的几个步骤: ? 二、页面置换算法 如果发生了缺页中断,就需要从磁盘上将需要的页面调入内存。 2.3 先进先出算法 顾名思义,先进先出(FIFO,First In First Out)算法的核心是更换最早进入内存的页面,其实现机制是使用链表将所有在内存中的页面按照进入时间的早晚链接起来,然后每次置换链表头上的页面就行了 时钟算法的核心思想是:将页面排成一个时钟的形状,该时钟有一个针臂,每次需要更换页面时,我们从针臂所指的页面开始检查。如果当前页面的访问位为0,即从上次检查到这次,该页面没有被访问过,将该页面替换。
volatile两核心三性质 两大核心:JMM内存模型(主内存和工作内存)以及happens-before 三条性质:原子性,可见性,有序性 volatile性质 保证了不同线程对这个变量进行操作时的可见性 为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的值读到内部缓存(L1,L2或者其他)后再进行操作,但是操作完不知道何时再写回内存。 ,在下次访问相同内存地址时,强制执行缓存填充,从系统内存中读取。 相反,它会锁定这块内存区域的缓存并回写到内存,并使用缓存一致性机制来确保修改的原子性,此操作被称为“缓存锁定”,缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据。 ,强制执行缓存行填充 小结 Lock前缀的指令会引起处理器缓存写回内存; 一个处理器的缓存回写到内存会导致其他处理器的缓存失效; 当处理器发现本地缓存失效后,就会从内存中重读该变量数据,即可以获取当前最新值
Github https://github.com/gongluck/Windows-Core-Program.git //第13章 内存体系结构.cpp: 定义应用程序的入口点。 // #include "stdafx.h" #include "第13章 内存体系结构.h" int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
Github https://github.com/gongluck/Windows-Core-Program.git //第14章 探索虚拟内存.cpp: 定义应用程序的入口点。 "指定的逻辑处理器共享一个处理器核心。ProcessorCore成员包含额外的信息。" (&memstatusex); memstatusex.ullTotalPhys;//物理内存总量 memstatusex.ullAvailPhys;//可分配的内存总量 memstatusex.ullTotalVirtual break; case MEM_RESERVE://指明页面被保留,但是没有分配任何物理内存。该状态下Protect成员未定。 break; case MEM_COMMIT://指明已分配物理内存或者系统页文件。
今天阿Q为大家准备了上好的“醒酒菜”——JVM运行时数据区的核心内存区——堆。 堆空间差不多是最大的内存空间,也是运行时数据区最重要的内存空间。堆可以处于物理上不连续的内存空间,但在逻辑上它应该被视为连续的。 堆内存大小设置 堆一旦被创建,它的大小也就确定了,初始内存默认为电脑物理内存大小的1/64,最大内存默认为电脑物理内存的1/4,但是堆空间的大小是可以调节,接下来我们来演示一下。 ❞ 启动程序 启动程序之后去jvisualvm查看 一旦堆区中的内存大小超过-Xmx所指定的最大内存时,将会抛出OOM(Out Of MemoryError)异常。 这是因为在堆内存存取数据时,新生代里边只有伊甸园和幸存者1区或者是幸存者2区存储对象,所以会少一个幸存者区的内存空间。
1、Linux 查看CPU核心数 cat /proc/cpuinfo | grep "model name" && cat /proc/cpuinfo | grep "physical id" ? 2、 Linux查看内存大小 cat /proc/meminfo | head -n 16 ? 3、Linux查看磁盘占用 df -h ?
今天阿Q为大家准备了上好的“醒酒菜”——JVM运行时数据区的核心内存区——堆。 堆空间差不多是最大的内存空间,也是运行时数据区最重要的内存空间。堆可以处于物理上不连续的内存空间,但在逻辑上它应该被视为连续的。 堆内存大小设置 堆一旦被创建,它的大小也就确定了,初始内存默认为电脑物理内存大小的1/64,最大内存默认为电脑物理内存的1/4,但是堆空间的大小是可以调节,接下来我们来演示一下。 一旦堆区中的内存大小超过-Xmx所指定的最大内存时,将会抛出OOM(Out Of MemoryError)异常。 这是因为在堆内存存取数据时,新生代里边只有伊甸园和幸存者1区或者是幸存者2区存储对象,所以会少一个幸存者区的内存空间。
很多用户在安装了PD虚拟机后,会觉得虚拟机内存太小,那么如何分配虚拟机内存呢?CPU核数该怎么设置? 具体操作如下: 1、点Mac系统左上方的苹果小标志,选择关于本机,可以看到此机的基本硬件信息,本机是六核的CPU和16G的内存 2、右键Dock栏的PD图标,选择控制中心 3、如果你的虚拟机正在运行 4、点齿轮图标,进入虚拟机配置,选择硬件,再选择CPU和内存,选择手动,酌情分配。 注意事项: 处理器和内存,建议设置成MAC电脑的一半,我设置了4核心和8G内存,可供参考。 Windows 11至少需要4G内存。 5、分配好后,关闭窗口,重启虚拟机即可。
如何定义这种分布式内存抽象,需要考虑多方面的因素: 分布式内存抽象需要具有传统分布式计算框架的优点,即自动容错、位置感知性调度和可伸缩性 将中间结果存储由磁盘转化为内存,提高迭代计算的性能 数据集不可变 RDD VS DSM 为了了解RDD作为分布式内存抽象的好处,将RDD与传统的分布式共享内存(DSM)进行了比较。 Spark 基本架构及运行过程 ---- RDD是Spark的核心,也是整个Spark的架构基础 与许多专有的大数据处理平台不同,Spark建立在统一抽象的RDD之上,使得它可以以基本一致的方式应对不同的大数据处理场景 缓存的RDD一般存储在内存中,但如果内存不够,可以溢出到磁盘。 RDD是Spark的核心,也是整个Spark的架构基础。
由于在主板上引入多个 cpu 插槽需要更复杂的硬件支持(连接不同插槽的 cpu 到内存和其他资源),通常只会在服务器上才这样做。在家用电脑中,一般主板上只会有一个 cpu 插槽。 核心(core) 一开始,每个物理 cpu 上只有一个核心(a single core),对操作系统而言,也就是同一时刻只能运行一个进程/线程。 为了提高性能,cpu 厂商开始在单个物理 cpu 上增加核心(实实在在的硬件存在),也就出现了双核心 cpu(dual-core cpu)以及多核心 cpu(multiple cores),这样一个双核心 因此认为文件中记录的 24 核心更加准确。 个核心,96线程,每个核心有2个线程。
Per.19: Access memory predictably Per.19:以可以预测的方式访问内存 Reason(原因) Performance is very sensitive to cache
C.180: Use unions to save memory C.180:使用联合体节约内存 Reason(原因) A union allows a single piece of memory 联合体使用同一块内存管理在存在于不同时刻的不同类型的对象。也就是说,当不同的对象永远不会同时使用的时候,使用联合体可以节约内存。
R.5: Prefer scoped objects, don't heap-allocate unnecessarily R.5: 范围对象不要在堆内存上构建 Reason(原因) A scoped in the ... part (leading to leaks), and verbose: 下面的示例是非效率的(因为它包含了不需要的分配和释放动作),容易抛出异常并且从...部分返回的话会发生内存泄露
前面已经分析了伙伴管理算法的释放实现,接着分析一下伙伴管理算法的内存申请实现。 其中for_each_zone_zonelist_nodemask()则是用于遍历zonelist的,每个内存管理区尝试申请前,都将检查内存管理区是否有可分配的内存空间、根据alloc_flags判断当前 CPU是否允许在该内存管理区zone中申请以及做watermark水印检查以判断zone中的内存是否足够等。 order, current_order, area, migratetype); return page; } return NULL; } 该函数实现了分配算法的核心功能 较正常的伙伴算法不同,其向迁移类型的内存申请内存页面时,是从最高阶开始查找的,主要是从大块内存中申请可以避免更少的碎片。
C.90: Rely on constructors and assignment operators, not memset and memcpy C.90:依靠构造函数和赋值运算符,而不是内存初始化和内存拷贝
如下图所示,现在我们决定创建一个属于我们的express文件,引入的express改成引入我们手写的express。 。
云桌面(Cloud Virtual Desktop,CVD),为您提供随需快捷交付的虚拟桌面服务。通过加密的自适应传输协议,构建业务安全访问入口,且最终用户可以获得优质的云桌面访问体验。云桌面服务可为您构建可靠的数字化工作空间,实现远程办公,提升业务访问的安全性和连续性。
扫码关注腾讯云开发者
领取腾讯云代金券