主题:动态数组频繁setlength出现EoutofMemory异常???
viphuangbin
[专家分:0] 发布于 2007-09-08 11:41:00
由于应用需要,需要一个动态数组存放未知长度(可能几千万个)的整数序列(用TList会多消耗很多内存),因此频繁修改长度,才到几万的时候就报内存错误,难道setlength()必须要有连续的内存空间才能分配成功吗,现举例如下:
var
myarray:array of integer;
i:integer;
begin
for i:=1 to 10000000 do
setlength(myarray,i);
end;
为什么明明一千万个整数,占的内存也就几十兆,却在有时候回出现EOutofmemory异常呢,而且当时应用软件的高峰内存才一百多兆.请高手指教!!!
回复列表 (共10个回复)
沙发
长尾兔 [专家分:3630] 发布于 2007-09-08 13:08:00
原样拷贝楼主的代码,经测试,WindowsXP + Delphi6 未出错。
板凳
xiaotian9 [专家分:60] 发布于 2007-09-08 18:13:00
根据楼主的代码,运行后无问题,本人也在Windows XP下,不过用Delphi 7而已.
看来不是代码的问题,问题应该在别的地方.
3 楼
viphuangbin [专家分:0] 发布于 2007-09-10 09:36:00
好心朋友没有明白我的意思,其实我写的这个代码不是要运行出错的代码,我只是举个例子(这段代码我这里也不会出错),实际的问题是,在一个需要大量使用内存的应用程序中,再用动态数组存放未知长度数据,而且需要非常频繁调用setlength()增加数组长度的时候,是否会有内存分配失败的情况。
小弟看到国外的一篇文章,讲到动态数组的每次增长量最好不要太小,比如象我的示例代码中的1,最好是几百,或者50%,尽量减少调用setlength()来增加数组长度的次数,这样不容易出现EoutofMemory异常,但该文章没有实际的办法解决问题。
我的问题还是,setlength(),增加数组长度,太频繁,并且次数极其多的情况下,是否会出现Eoutofmemory错误。
4 楼
viphuangbin [专家分:0] 发布于 2007-09-10 10:00:00
小弟再把绝对要出错的代码写出来:
procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
hashtable:THashedStringList;
myarray:array of integer;
begin
hashtable:=THashedStringList.create;
for i:=20000000 to 30000000 do
begin
if i mod 1000=0 then
begin
caption:=inttostr(i);
application.ProcessMessages;
end;
hashtable.Add(inttostr(i));
setlength(myarray,i);
myarray[i-1]:=i;
end;
hashtable.Clear;
hashtable.Free;
setlength(myarray,0);
myarray:=nil;
application.MessageBox('完成!','提示');
end;
我的机器是p4双核,内存1G,两三千万的数据应该能存放吧
5 楼
punkrocker [专家分:720] 发布于 2007-09-10 10:46:00
THashedStringList
我木有这个类。。。
6 楼
viphuangbin [专家分:0] 发布于 2007-09-10 12:48:00
THashedStringList 是inifiles里面的
7 楼
长尾兔 [专家分:3630] 发布于 2007-09-10 14:55:00
“我的机器是p4双核,内存1G,两三千万的数据应该能存放吧”
--------- 内存溢出往往是栈溢出。栈空间是非常宝贵有限的。你要做的极限测试我倒没有搞过,暂时也无兴趣搞。因此帮顶了。
8 楼
punkrocker [专家分:720] 发布于 2007-09-10 17:14:00
hashtable.Add(inttostr(i));
我不知道是干嘛用的
把这句注释掉,然后在myarray[i-1]:=i;后加memo1.lines.add(inttostr(array[i-1]]));是能读到给数组赋完20000000到30000000的值的,所以应该不是“频繁setlength”造成的问题
看看Hashtable的相关说明,是不是add的元素有上限什么的
我这里只要是5217000个元素就会出问题,内存728
9 楼
viphuangbin [专家分:0] 发布于 2007-09-12 15:08:00
楼上:
hashtable.Add(inttostr(i));
之所以加上这句,是想造成内存分配的“碎片”,不加这句,我的循环不会出异常的,除非内存真的不足了,但加上这句,只需要跑几万次,就报异常
10 楼
viphuangbin [专家分:0] 发布于 2007-09-12 15:19:00
这是我看到的国外的一个贴子
In article <4244e47...@newsgroups.borland.com>, Golddog wrote:
> Using Delphi 5 as a hobbiest:
> I've a dynamic array that keeps getting enlarged. Each record is 24
> bytes and when the array dimension reaches 13,600,000 or so I get an out
> of memory error. What if anything should I do?
Be a bit smarter in the way you enlarge the array. Each time you grow the
array the VCL and the OS have to find a new memory block large enough for
it to fit in, then copy the old content over to the new one. This is no big
problem as long as the current memory block the array resides in can be
extended, since the memory after it is still free. But that is frequently
not the case, so you end up with a massively fragemented memory space,
where large free blocks (which are not large enough to fit the new array,
though) are separated by small in-use blocks.
<font color=red>The only way to prevent that is to not resize the array in small
increments.</font> Instead, if you can come up with a rough estimate of what the
array size will eventually be, you set the size to that value up front
(SetLength) and then track yourself how much of that allocated space you
have already in use. When the array needs to grow eventually you do not
grow it by a small number of elements, you grow it, e. g. by 50% or even
double its size. This way you will end up with only a few growth events
(ideally only one at the start) and will not run into memory fragmentation
issues.
我来回复