找回密码
 注册
X系列官方授权正版
搜索
查看: 5849|回复: 9

[灌水] 不知道这样算不算一种变相突破单进程2G内存限制的方案?

[复制链接]
发表于 2013-11-2 19:26:43 | 显示全部楼层 |阅读模式
32位程序,一个进程最多只能占用2G内存(据说有指令可以加到3G,效果不明)。那么如果在编程的时候,设定成一次开启多个空进程。然后每个空进程获得两G内存用来储存游戏的数据。而主进程的内存空间里只储存最必要的核心文件和一些需要频繁读写的数据,剩下的空间就是大量的内存指针指向空进程的内存空间。毕竟内存指针比起它指向的文件要小的太多太多了。只不过好像Windows对跨进程的指针访问好像限制的很严。。。。。
发表于 2013-11-2 22:04:44 | 显示全部楼层
编译64位版本简单多了,何必呢
回复

使用道具 举报

发表于 2013-11-3 22:30:12 | 显示全部楼层
32位进程之所以只能用2G内存,并不是OS限制的,而是指针只有32位,所以只能寻址4GB(2^32)的地址空间。通常用户2G内核2G(或用户3G内核1G)。

你说的跨进程存储数据当然可以实现,但指针无法直接寻址的空间其实是没意义的。

如果无需直接寻址,其实有很多方法能实现内存扩容。最简单的方法就是自己实现交换文件,即做个大文件,然后要访问哪块就把那块映射到用户地址空间的一个窗口里,Windows会通过cache的方式来用到所有的物理内存。当然前提是系统得是64位的。

不知道楼主写过16位DOS程序没,和那时候的EMS是一个原理:将扩展内存的一块映射到1M地址空间内,用完了再映射另一块,如此不停交换以充分利用所有1M以上的物理内存。
回复

使用道具 举报

 楼主| 发表于 2013-11-4 19:20:03 | 显示全部楼层
ioncannon 发表于 2013-11-3 22:30
32位进程之所以只能用2G内存,并不是OS限制的,而是指针只有32位,所以只能寻址4GB(2^32)的地址空间。通常 ...


是指针只有32位
那么我最多有2^32个指针,而每个指针对应内存里的一个字节。
那么如果我不往主程序的内存空间里放整个文件。而是放一个指针指向空进程里实际存放数据的内存空间的第一个字节,那么我这2G的空间里就能放下2^32个指针,而每个指针可以指向一个任意大小的文件。然后当系统寻找某段数据的时候,利用指针+偏移量的方法来寻址。这样一来运行效率可能是会低一点,但至少绕开了内存空间限制了,比时不时的进行硬盘读写应该要快的多。

这跟用完一个换一个的做法还是有一点区别的。
回复

使用道具 举报

发表于 2013-11-12 19:42:58 | 显示全部楼层
FRIGHTER 发表于 2013-11-4 19:20
是指针只有32位
那么我最多有2^32个指针,而每个指针对应内存里的一个字节。
那么如果我不往主程序的内存 ...

对于现代操作系统来说,“读写内存”和“读写文件”不再是绝对的物理操作了,这只是操作系统抽象出来的虚拟动作。

程序在读写内存的时候,实际上只是在访问虚地址空间,而访问的地址不一定能映射到物理内存(缺页),此时操作系统就会去替你访问交换文件,只是程序感觉不到(仅仅卡一下而已)。

而程序在读写磁盘文件的时候,实际上操作系统会帮你维护一个磁盘缓存(这个缓存并不局限于地址空间大小,而是能利用全部物理内存的)。如果你是用内存映射的方式,那访问文件就和访问内存一样方便(读写相应内存区域会直接反应到文件上)。

所以说,我们程序中的所谓“内存操作”并不是一定比所谓“文件操作”快的。如果让我做个能突破2G空间的32位程序,我会选择内存映射文件,因为我觉得这样实现起来简单。

当然萝卜青菜个人所爱,coding和写文章一样没有标准答案,我并不反对你的做法。
回复

使用道具 举报

 楼主| 发表于 2013-11-13 06:33:42 | 显示全部楼层
ioncannon 发表于 2013-11-12 19:42
对于现代操作系统来说,“读写内存”和“读写文件”不再是绝对的物理操作了,这只是操作系统抽象出来的虚 ...

难道我对文件读写的理解错了么。。。

我一直以为游戏之类的程序的做法是把数据/文件根据使用一定的顺序(比如使用频率啊之类的)尽可能的存进内存。然后当需要的时候如果内存里有这个文件那么程序就可以直接从内存取用。而如果需要的文件没有读入内存那么就只能从硬盘上读取,于是在等待磁盘寻道和读写的时候就会造成掉帧和卡顿的现象。所以在其他配置不变的情况下,内存大的电脑在游戏中会比较流畅因为更多的文件在内存里,读写硬盘的频率更低。
回复

使用道具 举报

发表于 2013-11-13 11:58:46 | 显示全部楼层
LZ是在写论文么,还是纯学术讨论?
撸过~

点评

连学术都算不上,突发奇想而已  发表于 2013-11-22 21:49
回复

使用道具 举报

发表于 2013-11-14 00:24:03 | 显示全部楼层
本帖最后由 ioncannon 于 2013-11-14 00:40 编辑
FRIGHTER 发表于 2013-11-13 06:33
难道我对文件读写的理解错了么。。。

我一直以为游戏之类的程序的做法是把数据/文件根据使用一定的顺序 ...


楼主大大我不知道您平时都喜欢用什么语言来写程序。如果您用C/C++并且只用STL来访问内存(malloc、new)和读写文件(fopen、iostream之类)的话,那您对内存访问和文件读写的理解是对的,就像教科书上说的那样,此时文件几乎总是比内存慢,那您大可以忽略我说的话。Java、C#情况类似。

但如果您用C/C++并直接调用Windows API的话,这里就有很多事情可以干,也很多工具可以用了。比如可以用VirtualAlloc来精细地控制每一片内存的保留、提交状态,可以用CreateFile通过各种方式创建/打开文件,微调文件缓存行为。如果程序设计精良的话,通常可以使程序比只用STL的程序快许多。这种情况下,内存快还是文件快就不一定了,这取决于参数的设定。只要文件缓存命中,就无需读写磁盘;反之如果内存发生缺页,就会产生磁盘寻道和读写。最终的速度取决于是不是真的产生了磁盘操作,而非取决于一开始是内存操作还是文件操作。

当然,通常情况下内存操作还是快的,但这是在内存用量不大的情况下。您大可写个简单的程序,不停地分配等大小的内存块并进行随机读写,记录每次分配用的时间。您会发现一开始分配内存增长速度几乎是线性的,内存以相等的时间被分配出来。但到了某一个大小(大概1G多吧,不同机器配置不一样)时,速度一下子就下来了,新内存分配时间显著延长,此时硬盘灯开始狂闪,这就是内存缺页。Windows不会让一个进程独占那么大物理内存的,即使物理内存是够的,它必须平衡所有进程的内存使用。Windows搞了个工作集(WorkingSet)来控制每个进程能占多大物理内存,超过了系统就开始把你之前分配的内存往页面文件里塞,于是产生了磁盘操作,内存访问就慢了。

更糟糕的是,系统没那么智能,很有可能它塞到页面文件里的内容正好是你接下来要访问的,好吧,系统马上又要把刚才那页内存从磁盘里读出来,再选另一页内存写入页面文件。。。于是程序和系统就在纠结中不停地读写磁盘,但其实此时程序只是在访问内存,一个文件都没打开呢。

我在上学的时候曾经做过游戏修改器,类似CE的东西。修改器你懂的,扫描目标进程的内存空间,把符合条件的结果记下来。如果是低阶扫描初始化,那就要记下整个内存。有的游戏动辄1G内存占用(那时候还没64位系统),全记下来结果集是很大的。一开始我就把结果全放内存,心想反正Windows会打点一切,结果我错了,虽然一开始很快,但扫描到后面几乎进行不下去。因为随着我分配内存增多,换页频繁不说,还会挤占目标游戏的内存,但那些被挤占的游戏内存还要被扫描呢。于是整个机器就卡死了,只能听见硬盘狂转的声音,费了好大劲才打开了任务管理器杀了我的进程,系统才慢慢缓过来。后来我改用文件来保存结果,关闭磁盘缓存,并用异步读写模式解决了这个问题。虽然扫描一开始不如原来用内存快,但整个扫描过程都是匀速的,内存很稳定不会有很多换页。

抱歉罗嗦了怎么多,我只是想说并不是将尽可能多的数据/文件搬到内存来访问就一定会快(当然通常时候是会快的,这毕竟是程序基本设计思想)。如果不小心而又无意识地占用了过多内存,系统就会给你帮倒忙,虽然表面上看起来物理内存是够的。而内存大的电脑在游戏中会比较流畅是因为内存换页少,同时文件缓存更大更容易命中。

最后再插一句玩笑话:你知道为什么程序访问的内存叫虚拟内存吗?因为内存确实是虚拟出来的,对于给定一个时刻一块内存,你不知道它是在真的物理内存上还是在磁盘交换文件上。只有操作系统才知道。
回复

使用道具 举报

 楼主| 发表于 2013-11-22 21:49:21 | 显示全部楼层
ioncannon 发表于 2013-11-14 00:24
楼主大大我不知道您平时都喜欢用什么语言来写程序。如果您用C/C++并且只用STL来访问内存(malloc、new) ...

是的,我就是针对Windows不会允许一个进程占用太多内存的这个问题。所以我设想的是开多个进程,每个进程都申请一片“内存”空间,这样就能获得更多的实际内存了。。。。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

Archiver|手机版|小黑屋|DeepTimes.NET 太空游戏站