内存管理(AWE)——完成端口通讯服务器(IOCP Socket Server)设计(二)

IOCP的内存管理 IOCP内存管理换上了log4cplus日志系统,记录发现有些情况下的io和完成key没有回归队列,多处释放又怕导致重复入队列。先转贴两篇网上的文章:IOCP中的socket错误和资源释放处理方法前言:   错误处理和socket释放, 是IOCP编程中的一大难点. 本文试图就IOCP设计中经常遇到的这个难题展开论述并寻找其解决方案, 事实上, 文中所述的解决方式不仅仅适用于IOCP, 阅读详情

 

完成端口通讯服务器(IOCP Socket Server)设计

(二)内存管理(AWE)

 

Copyright © 2009 代码客(卢益贵)版权所有

QQ:48092788   源码博客:http://blog.youkuaiyun.com/guestcode

论坛讨论连接:http://topic.youkuaiyun.com/u/20090827/02/51572fda-5cd3-4c6f-9b63-01dd5cc9738a.html

 

有牛人曾经说过,服务器玩的就是内存。仔细想想,确实是如此。服务器对内存的需求是巨大的,对内存的要求也是苛刻的。如何在内存管理上下功夫使服务器性能达到一个质的飞跃,是服务器设计中的首要解决的问题。

说到内存,我想刚开始设计服务器的人会说,不就申请释放吗,有什么难呢。从操作步骤来说,确实就这么两个,没有再多了的工作了。当我们采用虚拟内存分配或堆分配从操作系统获取内存的时候,总以为我们获得了足够的内存就可以让服务器安心工作了。但事情并未就这么简单,操作系统在一定条件下,还可以征用已经分配给你的物理内存,它会将你的物理内存数据复制到页交换文件中,然后把本来给你的物理内存再分配给别的进程,当你的进程访问你所获得的虚拟地址集的数据时,它会再找个空(或许也是从别的进程征用)的物理内存,再从页交换文件里面调出你原来的数据放回到新的物理内存里面,并将这个物理内存映射到你申请的虚拟内存地址集内(有关这项内容请参考操作系统的内存管理)。这个过程是相当耗费CPU资源且十分缓慢的,尤其是对硬盘虚拟内存文件的读写。其它大道理本文不多说,关于操作系统内存管理的原理可以从《Windows核心编程》、《Windows操作系统》、《操作系统》等书籍上了解。

我们可以使用lookaside lists技术来重新使用已经分配的内存的,或者使用SetWorkingSetSize来设置标志告知操作系统不要交换我的内存,但不外乎多一次操作而已。这个操作到底消耗多少的CPU资源,本人也没有考究过,但从性能要求的角度来说,多一事不如少一事。本文讨论的内存管理,将采用AWE(地址窗口化扩展)的技术,将申请到的物理内存保留为非分页内存,这部分的内存不会被页交换文件所交换,关于AWE请参阅以上提到的书籍。(下面提到的“内存管理”,将仅针对应用程序自己的内存管理功能模块(下文称之为内存管理器)而言,已非上面提到的操作系统的内存管理。)

衡量内存管理器性能的有两个,一个是内存分配时的效率(分配效率),另一个内存交还时的效率(释放效率),亦即二者操作的时间性,这个时间越短那么可以认为它的效率越高。下面的讨论,假定内存管理器是以页为最小分配单位,至于页的大小是多少才合适,稍后再说。

先谈分配效率(下面提到方法仅为本人归纳后的方法,不是学术上的算法):

1、单链表型

也就是将所有空闲内存块(即空闲内存碎片,下称空闲碎片)组成一个空闲碎片链表。当提出内存分配申请的时候,从这个链表头遍历查找合乎要求的内存或从大的碎片里面分割出来。这个方式简单,但如果空闲碎片多而且小于申请要求的时候,就需要做众多的循环操作。

单链表型排列方式可分为:

a按地址高低排列 n

b安碎片由小到大排列

c不排列(先进先出)

2、多链表型

事实上,多链表型就是将上述按b方式排列的单链表,根据一定的大小档次截断而组成的多个链表集(相关算法请参阅上文提到的书籍)。

多链表我将之分为a、b型。

a型如下表:

 

从上表我们看到,0~<4K的ListA有8个碎片节点;4K~<8K的ListB有4个碎片节点,分别是:4K、6K、7K、7K;8K~<16K的ListC为空;16K~<24K的ListD有4个碎片节点,分别是:16K、19K、22K、23K。

假如要分配一个5K的内存,就可以直接从ListB查找(如果ListB为空,则继续向更大空间的链表查找)直到底部的ListN。这样就可以避免遍历ListA,假如ListA碎片极多的情况下那么就可以节省更多的时间。

 

 

b型如下表

 

 

右边的情况不多说,基本和a型的一致。那么左边的映射表是怎么回事呢?映射表始终没有空的,如果ListA不为空,那么a就指向ListA,如果ListA为空,那么它再指向ListB,以此类推直到底部的ListN。如果要分配9K内存,直接从c取链表头,实际上它指向的ListN,这样当N =1000+的时候,节省的时间就和a型相比就非常可观了。

再看看释放效率:

1针对内存分配方案的第1种类型

释放步骤为:

a找到比释放内存块的地址低的并是相连接的空闲碎片然后与之合并再重新排列;

b不管a成立与否,再找比释放内存块的地址高的并是相连接的空闲碎片然后与之合并再重新排列;

c在a和b不成立的情况,则按排列规则插入空闲碎片链表。

上述步骤中,我们发现空闲碎片是一个巨量级的时候效率及其低下。

2针对内存分配方案第2种类型

a从ListA到ListN找到比释放内存块的地址低的并是相连接的空闲碎片然后与之合并再重新排列;

b不管a成立与否,再从ListA到ListN找比释放内存块的地址高的并是相连接的空闲碎片然后与之合并再重新排列;

c在a和b不成立的情况,根据释放内存的大小找到归档链表,按排列规则插入该空闲碎片链表。

在这个情况中,工作量比起1更加大的多。

3内存块链表法

这个链表不是指上面所说的空闲碎片链表,而是所有的内存不管空闲的或是使用的,按地址由低到高排列的双向内存块链表。当然,我们不能在释放的时候再去排列所有的内存块,这样的话效率也是相当低的。

如何排列这个链表,可以从分配的时候下功夫:

pBlock为空闲的碎片块

……

if(pBlock->dwSize > dwSize)

         {//如果空闲块的大小大于要分配的

              //从大的里面切出一块来使用,该块容量减少

              pBlock->dwSize -= dwSize;

              //返回分配的地址

              Result = (PGMEM_BLOCK)pBlock->pAddr;

              //该空闲块向后指向新的空闲地址

              pBlock->pAddr = (char*)Result + dwSize;

              //获取一个新节点

              PGMEM_BLOCK pTmp;

              pTmp = pmbGMemNodePool;

              pmbGMemNodePool = pmbGMemNodePool->pmbNext;

              //将新分配出去的块插在该空闲块前面

              pTmp->pAddr = Result;   //分配出去的内存块地址

              pTmp->dwSize = dwSize;   //分配出去的内存块大小

              pTmp->pmbNext = pBlock;  //下个指针指向被分割的空闲块

              pTmp->pmbPrior = pBlock->pmbPrior; 

              if(pTmp->pmbPrior)

                   pTmp->pmbPrior->pmbNext = pTmp;

              pBlock->pmbPrior = pTmp;

……

         }

根据上述代码,在分配的时候只需很少的代码量就可以完成了排列要求,这个小小的开支,就可以在释放的时候起到非常高的效率:

从上图看到,内存块链表顺序是:ABCDEFG,空闲块链表顺序是:EBG。通过要释放的块的地址经过计算(FreeAddr –AddrHead)/ PageSize得出该块在页标志的位置,就可以找到要释放的内存块在内存块链表中的位置是F,通过上下指针就可以知道与F相邻的两个块是EG,根据标志判断是否为空闲块,然后通过双向链表操作来合并这个三个块,这样几乎不要任何遍历操作就可以轻松完成了释放合并的操作。当然如果相邻两个块都没有空闲的,则按排列规则插入空闲块队列。估计没有比这个更好的释放合并内存的算法了。

经过了上面的方法介绍,这个时候我们应该清楚我们该做什么了吧。如果采用内存分配第2种“多链表b型”的方案和内存释放第3种“内存块链表法”的方案,那么这个内存管理器一定是优越的吧。于是开始噼里啪啦的编码……发现一个头痛的问题,即使把内存释放的工作让独立线程来处理,空闲内存块的排列依然消耗很多时间。这个时候不禁问:我们到底在干什么?用这么强大的内存管理器来做操作系统吗?不,我们不是做操作系统,那还有什么方法让内存管理更为简单呢?

来看下表,一个应用服务器对内存动态需求量的统计表:

 

看了上面这个表终于明白,原来在内存需求中类型为F和G的最多,似乎豁然开朗,假定内存足够的情况下将内存管理器的页大小设置为512B,那么即使空闲内存块是不排列的,分配内存的效率也是极高的。但对类型D这个使用频率最高的内存需求怎么解决呢?任何只想使用一个内存管理器就能做好服务器的想法是错误的。针对很多种内存需求,必须加以分类。针对这个4K内存需求,可以使用一个固定大小的内存池来解决,只要是这个内存类型需求的都要在这个内存池操作,比如Socket I/O操作的缓冲区等(将在以后介绍)。

通过以上讨论,采用内存分配方案的第1种类型c方式排列和内存释放方案第3种类型,来满足不固定大小的动态内存分配需求,即可一定程度上达到对性能要求的目的。当然,使用内存分配方案的第2种b类型的,也未必不可,多消耗些CPU资源而已。

内存管理没有绝对的方法,所以上述内容仅仅是讨论如何根据内存需求设计内存管理器。

例程截图:  

 

 


源码说明:

GMem.cpp和GMem.h是内存管理单元的源码文件,欢迎指正。历程源码没有优化,能达到测试目的即可,提供的测试数据仅供参考,并无实质意义。

 

例程源码下载:

 

http://download.youkuaiyun.com/source/1607811

 

 

 

 

 

 

 

  

 

  ....

IOCP 内存池线程池的一个例子 IOCP 内存池线程池的一个例子 主要优化在性能上 包括IO收发的重叠结构用了内存池技术 立即下载

相关推荐

真正无锁IOCP回射服务器(IOCP Tcp EchoServer)

基于IOCP模型的无锁0内核态TCP通讯服务器引擎(IOCPTCP Server)

别再让Jenkins裸奔了!手把手教你配置安全认证,堵上未授权访问的漏洞

本文详细介绍了如何为Jenkins配置安全认证,防止未授权访问漏洞。通过矩阵式安全策略、密码强化、网络层防护和运行时监控等多维度措施,构建企业级防护体系,确保Jenkins在持续集成中的安全性。

weixin_30315723的博客 491

【锂离子电池力学耦合及相场法模拟技术与应用】

8. 电化学仿真软件的使用与案例分析 (1) 各向异性纳米线锂化应力分析(实例讲解1) (2) 化学反应及死锂现象研究(案例分析2)(3) 锂化循环损伤计算(案例分析3)6. 4. 电池材料的力学与电化学耦合性能分析(1) 耦合效应对电池性能的影响(2) 耦合模型的验证与应。5. 5. 电池颗粒、极片、电芯尺度力-电-化-热多场耦合模型概述力学-7. 颗粒尺度耦合模型在电池失效分析中的应用。2. 2. 电池电极材料的分类与特性。5. (2) 耦合模型的验证与应用。电化学耦合模型与仿真。

weixin_51101456的博客 520

AWE /3GB 内存扩展技术

转载于:http://blog.sina.com.cn/s/blog_600ffbf20100gy6w.html Address WindowingExtensions Widnows中的Address WindowingExtensiongs功能允许应用程序存取超过4GB的物理内存。32位的指针是一个整型,只能够存储小于等于0xFFFFFFFF的值,因此只能够引用一个4GB的线性内存地址

fangjian1204的专栏 1863

将pytorch的权值矩阵量化为定点数补码并导入FPGA中

Xilinx FPGA实现LSTM算法时对ROM的初始化 将pytorch框架的权重矩阵以定点数补码的形式导入到FPGA中 文章目录Xilinx FPGA实现LSTM算法时对ROM的初始化1. pytorch框架中的LSTM2. 初始化一个RNN模型 3. 初始化ROM的coe文件格式 4. 将参数转换为补码,并且输出到coe文件 5. 配置一个ROM 6. 结论7. 代码 1. pytorch框架中的LSTM pytorch框架将LSTM算法中的八个权值矩阵连接成两个矩阵,假设要导入的LSTM网络的输

随缘分享 4527

基于Android平台下的健康管理APP/基于android的健康管理系统

随着网络科技的发展,移动智能终端逐渐走进人们的视线,相关应用越来越广泛,并在人们的日常生活中扮演着越来越重要的角色。因此,关键应用程序的开发成为影响移动智能终端普及的重要因素,设计并开发实用、方便的应用程序具有重要的意义和良好的市场前景。Android技术作为当前最流行的操作平台,自然也存在着大量的应用服务需求。 本课题研究的是基于Android技术平台的健康管理APP,开发这款健康管理APP主要是为了帮助用户可以不用约束时间与地点进行所需信息。本文详细讲述了健康管理APP的界面设计及使用,主要包括界面的

m0_73706453的博客 1437

七、内存优化(1)启用AWE

一、内存体系结构1. 32位操作系统与PAE  在 32 位操作系统中,可以访问 4 GB 的虚拟地址空间。2 GB 的虚拟内存专用于进程,由应用程序使用;2 GB 保留给操作系统使用。   在 Boot.ini 文件中使用 /PAE 开关,启用PAE(物理地址扩展)才能利用超过 4 GB 的内存。最多可以访问到64GB物理内存。2. AWE  SQL Server 支持地址窗口化扩展插件 (AW...

weixin_34414650的博客 336

遥感常用相关指数和计算方法(植被指数/水体指数/雪和冰指数/矿物指数/地表温度指数/云和阴影指数/农业指数)

遥感常用相关指数和计算方法(植被指数/水体指数/雪和冰指数/矿物指数/地表温度指数/云和阴影指数/农业指数)

m0_64361769的博客 1万+

编写完成端口网络服务器的一些说明 (1)

 1. AcceptEx: BOOLPASCAL FARAcceptEx (   IN SOCKET sListenSocket,   IN SOCKET sAcceptSocket,   IN PVOID lpOutputBuffer,   IN DWORD dwReceiveDataLength,   IN DWORD dwLocalAddressLength,   IN DWORD

sun201201的专栏 802

Ubuntu上通过FinalShell或Asbru访问CentOS虚拟机

使用FinalShell或Asbru远程连接虚拟机

howard2005的专栏 2275

搭建 Newman + Postman + Git + Jenkins 环境教程

一步步搭建 Newman、Postman、Git 和 Jenkins 的环境。这些工具常用来做 API 测试和 CI/CD 自动化,尤其是 Postman 和 Newman 搭配 Git 和 Jenkins,能实现 API 集合的版本管理和自动测试。

Criss@陈磊 434

完成端口详解

完成端口详解  完成端口详解(4)2007年01月27日 星期六 15:34放在一起看看      以上各节中,我们讨论了开发高性能的、大响应规模的应用程序所需的函数、方法和可能遇到的资源瓶颈问题。这些对你意味着什么呢?其实,这取决于你如何构造你的服务器和客户端。当你能够在服务器

520

PX4从放弃到精通(三):使用qt编译PX4

1 下载px4源码 2在Firmware所在目录下执行 mkdir Firmware-build cd Firmware-build cmake …/Firmware -G “CodeBlocks - Unix Makefiles” -DCONFIG=nuttx_px4_fmu-v5_default 第三步最后的px4_fmu-v5_default根据自己的情况修改 执行完后如图 打开QT 点击打开工程 选择源码的CmakeLists.txt文件 选择imported Kit 打开项目那一栏,构建目

超维空间科技的博客 1万+

代码客:G-Socket(IOCP) 1.0(Server/Client)例程源码+Server体验程序+强大的压力测试工具

代码客:G-Socket(IOCP) 1.0(Server/Client)例程源码+Server体验程序+强大的压力测试工具关键词:完成端口 IOCP GSocket GTcpServer GTcpClient 压力测试工具 模块结构层次及相互联系(1)、工作线程:响应连接的IO投递返回并负责投递读请求,并将IO返回结果投递给处理线程,可设定参数决定

码客 卢益贵 ygluu 7542

KingSCADA实现按钮点击效果

哈喽,你好啊,我是雷工!在做SCADA项目的时候,按钮是不可缺少的功能,但软件自带的按钮太丑,已经无法满足现如今客户对界面美观度的要求。这时候就需要UI小姐姐设计美观大气的SCADA界面,但UI设计的按钮切图放到程序中只是图片素材,当添加了按钮功能时,虽然能实现按钮功能,但没有任何点击效果;当遇到有需要连锁条件才能点击的按钮时,操作员无法区分是有连锁点击了没反应,还是系统界面卡死了导致的没点击成功,这时候有点击效果就能很好的区分这种问题。本篇介绍一种实现按钮点击效果的方法,以下为操作过程。

做有价值的事,积累有价值的笔记! 2764

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

delphi,IOCP之内存分配池[1]

不费话上代码   {******************************************************************************} { @UnitName     : uVirtualMemPool.pas                                          } { @Project      : QsIOCP

Im17benteng的专栏 1836

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

用“卡尔曼滤波器”来处理“加速度计数据”(加速度,陀螺仪调试)

关键词:SCA3000,ADIS16255,加速度计、陀螺仪数据计算处理算法,卡尔曼滤波器、扩展卡尔曼滤波器。关键词:加速度计和陀螺仪驱动,SCA3000,ADIS16250,ADIS16255,温度、重力加速度、角速度计算方法,SPI总线,SCA3000 模式设置(Mode)、参数设置、读写,ADIS16255读写、参数设置,陀螺仪数据处理 SCA3000,ADIS16255,加速度计、陀螺

码客 卢益贵 ygluu 2万+

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

linux安装nginx并设置https(openssl)

一、安装依赖包 1.$sudo apt-get install openssl    或者$sudo apt-get install libssl-dev 2.$sudo apt-get install libpcre3 libpcre3-dev 二、安装nginx 1.$cd /usr/local/src 2.sudo wget http://nginx.org/download

码客 卢益贵 ygluu 2万+
上一篇: 是谁神化了IOCP——完成端口通讯服务器(IOCP Socket Server)设计(1)
下一篇: 不要迷信API(单链表的另一种算法)——完成端口通讯服务器(IOCP Socket Server)设计(三)
ygluu
博客等级 码龄17年 300粉丝 62原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值