完成端口内存池设计时的想法,请大家看看我想的对不对

badbadbad 2010-03-12 10:48:17
加精
最近在写高并发服务器用到了完成端口:

1、完成端口对输入输出的处理需要预先申请一个Overlapped缓存空间,并且要保持该缓存所在页面一直呆在物理内存里(一个页面大小根据情况有所不同,我的破电脑页大小是4K,也就是说如果你有一块Overlapped缓存虽然只有100个字节,但是整个4K的页都必须呆在物理内存里),而不是像一般空间一样可以被系统随意调度出物理内存(windows内存管理机制:长时间不用到的页会从物理内存中转出),但是这带来一个问题:如果输入输出请求量过于巨大,则导致被锁定的页太多,从而使的物理空间被占满影响到其他程序的运行,甚至完成端口本身也无法响应请求。(虽然windowsNT会对锁定页面做限制:即大概是不能超过物理内存空间的1/8)。

2、每次进行I/O操作时都要申请新的内存,用完后再释放,显然是非常影响运行效率的,而且也会产生大量的内存碎片。所以一般情况下高性能的服务器要求:在程序运行之初先把需要用到的内存全部申请好,每次需要内存的时候直接拿来用就可以了,等到程序退出的时候再把内存一次性释放掉。-----这个就是内存池技术。

我从网上看了很多人的内存池代码,发现他们有一个比较大的缺陷:他们的内存池不是一整块申请,而是一小块一小块申请,比如:

for i := 2 to IO_MEM_MAX_COUNT do
begin
PUNode(IOMemLast)^.Next := HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(TIOMem));
IOMemList[i] := PUNode(IOMemLast)^.Next;
IOMemLast := PUNode(IOMemLast)^.Next;
end;

我觉的这样申请的内存有一个很大的问题:由于这些一块一块的内存不是一起申请的,所以地址是不连续的,也就是这些内存会分散在不同的页中,这样就导致被锁定在物理内存中的页无形中多了很多,这应该很好理解的。

所以我认为应该一次性申请地址空间连续的内存,这样整齐的内存会减少很多被锁定的页面。

------------------------------------------------不一定成熟的想法。
...全文
2986 129 打赏 收藏 转发到动态 举报
写回复
用AI写文章
129 条回复
切换为时间正序
请发表友善的回复…
发表回复
zou_cplus 2011-09-04
  • 打赏
  • 举报
回复
hulose
说的不错 就现在而言 服务器的内存是足够用了 用固定大小的内存池 能够提高使得应用程序不用频繁的申请和释放空间。还有不会产生内存碎片。试想一下 你的服务器开一个月 因为内存碎片就要重启一次。这样还能做服务器吗
jasonke 2010-11-09
  • 打赏
  • 举报
回复
交给 fastmm, 并使用 getmem 代替 HeapAlloc ,一切问题解决, fastmm对碎片管理非常好
p2p_soft 2010-09-25
  • 打赏
  • 举报
回复
沙发,学习中
萨弗迪发个 2010-09-18
  • 打赏
  • 举报
回复
其实这个那个。我是来拿分的。!
yangtao639999 2010-07-27
  • 打赏
  • 举报
回复
正在学习 ,占位~
hulose 2010-07-17
  • 打赏
  • 举报
回复
我最近刚完成 一个IOCP模型的TCPServer

内存池 16K为最小 然后 64, 128, 256K最大 大于256K的采用动态申请(因为理论业务包不大可能达到这么大 就算有数据包很大 也肯定要拆解为小包来通讯)

比如 16K包做为 AcceptEx投递 以及 WSARecv接收用

其它大小(包括16K) 用于 发送

小于16K的的数据 就用16K 小于32K的数据 用 32K 以此类推

或许有人会说 那是不是很浪费内存?

那是肯定会浪费一些的 不过 你不要忘了 现在的服务器 小的至少4G内存 8G内存的遍地都是

16K 申请1w个好了 也不过160M而以 其它的 可以跟据自己的业务包 大小比例 业务使用频繁率 决定初始化个数

牺牲容易换取性能 这是值得的

再说了 可能你的业务量根本用不了申请这么多的量

你能保证你的连接数能达到 一定的量再说吧 你要记得一点 你开发的是服务器 不是拿PC去思考

当然 回过来想 怎么样最合理 什么样最优化 最终还是要考虑的 不过那些都是后事了


hulose 2010-07-17
  • 打赏
  • 举报
回复
在中小型的系统下 其实根本 不用太在意这个

内存池完全 可以 按定长申请 无需用多大 就是申请多大

如果你可以把池中缓冲区默认 分为 如 4K 8K 16,....256K

跟据需求 分别申请最合适的
lapal 2010-03-23
  • 打赏
  • 举报
回复
好东东,学习了
shify2000 2010-03-21
  • 打赏
  • 举报
回复
学习了,,
lin_style 2010-03-21
  • 打赏
  • 举报
回复
[Quote=引用 116 楼 babyboy 的回复:]

完成端口?上个世纪的技术,怎么还有人再用?设计大并发,你还用Windows?epoll,libevent,ACE都是现成
设计大并发服务器的技术,ACE的内存池,APR的内存池都是现成的东西,不要再自己发明砖头了。
[/Quote]

讲讲原理?
babyboy 2010-03-19
  • 打赏
  • 举报
回复
完成端口?上个世纪的技术,怎么还有人再用?设计大并发,你还用Windows?epoll,libevent,ACE都是现成
设计大并发服务器的技术,ACE的内存池,APR的内存池都是现成的东西,不要再自己发明砖头了。
ysr1980 2010-03-19
  • 打赏
  • 举报
回复
我觉得可以这样处理, 首先申请一块大小为A的内存池,然后做一个链表组freeLists[N]来管理对内存池空间的申请和释放管理,链表组分别管理大小为8、16、24、...(大小根据实际需要调整),当你申请20Byte的空间时,就从freeLists[20/8]的链表上取空的空间,如果没有,从内存池中申请24Btye空间。当内存池的大小A用完时,从新申请一块新的内存空间,这里的处理视情况而定,可以申请一块2A空间,而后把A中的数据拷贝到新的空间里,释放原来的空间,不过这种情况下注意指针的失效;也可以再申请一块A大小的空间,不过要一个新的链表来记录2块内存,便于释放。当然,还有一些细节要考虑,比如,当你申请20Btye的空间时,24链表上没有空间,内存池也没有空间,但32的链表上有空间,此时需要将32Btye拆分成8+24,再去链表上申请空间,而不是申请新的空间等等。大致的算法就是这样, 具体看情况做修订和改型。最近在做一个共享内存的实现vector效果的东西,感觉和你的有点相似,供楼主参考。具体参考《STL源码剖析》2.2.6第二级配置器__default_alloc_template剖析 ,根据它的算法改型。记得给分^o^
supview 2010-03-19
  • 打赏
  • 举报
回复
关注,不知道哪里有IOCP的开源项目可以学习下!
精锐掷矛手 2010-03-19
  • 打赏
  • 举报
回复
[Quote=引用 117 楼 cyblueboy83 的回复:]
恩,使用内存池的方法也不失是一个好方法

不过一般的做法应该都是事先给每个节点分配 一定大小的缓存,例如 1M..
[/Quote]
节点1M是不是太大了?
herman~~ 2010-03-19
  • 打赏
  • 举报
回复
恩,使用内存池的方法也不失是一个好方法

不过一般的做法应该都是事先给每个节点分配 一定大小的缓存,例如 1M..
HiIan 2010-03-18
  • 打赏
  • 举报
回复
学习学习,谢谢!
wfl568 2010-03-18
  • 打赏
  • 举报
回复
先Mark一下,看高手解答
chengwanfei 2010-03-18
  • 打赏
  • 举报
回复
不错 学些了 哈哈
woainihuajia 2010-03-18
  • 打赏
  • 举报
回复
learning.......start learning
heweilin 2010-03-18
  • 打赏
  • 举报
回复
学习 呵呵
加载更多回复(106)
Re:CCNA_CCNP 思科网络认证 PAT NAT 端口或地址转换 与端口映射======================# 本章课程大纲        公网地址和私网地址        NAT应用场景        静态NAT  :static  地址转换        动态NAT  :dynamic地址转换        PAT        :端口地址转换        端口映射 :port map        在Windows上同实现的NAT和端口映射 # 私网地址三类 A类:10.0.0.0                                255.0.0.0(1网段) B类:172.16.0.0 -172.31.0.0         255.255.0.0(16网段) C类:192.168.0.0-192.168.255.0  255.255.255.0(255网段) # NAT 的使用场景        NAT的最初的目的是允许把私有IP地址映射到公网地址,以减缓IP地址空间的消耗。        当一个组织更换它的互联网服务提供商ISP,但不更改内网配置方案,NAT同样很有用途。        以下是适于使用NAT的多种情况:         企业内网接入Internet节省公网地址         单向访问         大方向:内网访问互联网(互联网上主机不能够访问内网主机)         小方向:同单位实现两个网段之间单向访问(涉密部门能够访问其他部门,反之不可)         增加一个网段          避免在主干路由器增加到这个网段的路由         在Windows上实现的NAT和端口映射 # 网络地址转换的类型        下面介绍一下NAT的三种类型。         静态NAT 是为了在私网地址和公网地址间,允许一对一映射而设计的。         或者IPv4和IPv6之间的转换(典型)         不节省公网地址,故公网地址的利用效率不高,         无任何安全性,外网可以通过公网地址直接攻击内网主机,好像只增加路由器的工作         适用场景类似代理,可以较方便的更换主机,而无需修改路由器的配置         故应用不够广泛...         动态NAT 可以实现映射一个未注册 IP地址到注册IP地址中的一个注册IP地址。         多对一,或多对多         比较PAT优势:避免被误认为攻击而被封ip地址         不太节省地址,应用不广泛         复用是最流行的NAT配置类型,也被称为端口地址映射(PAT)。         通过使用PAT,可实现上千个用户仅通过一个真实的全球 IP地址连接到Internet。         缺点:增加延迟,消耗路由器性能 # 端口映射(port mapping) 允许Internet上的计算机通过企业路由器的公网IP地址访问到内网的服务器------------------------------------------------         

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧