急,频繁调用setlength()增加数组长度的EoutofMemory异常!!!! ( 积分: 100 )

  • 主题发起人 主题发起人 xhuangbin
  • 开始时间 开始时间
X

xhuangbin

Unregistered / Unconfirmed
GUEST, unregistred user!
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;
我的机器是1G的内存,但该代码才执行几秒,就出现out of memory错误,请教高手,动态数组的内存分配是否必须是连续的内存空间,什么情况下会出现EoutofMemory异常呢。
 
超出2gb了
进程空间虚拟内存大小是4gb,其中2gb保留给系统
 
应该是超出了,SETLENGTH自己会释放的
 
SetLength函数会先分配新大小,然后把旧数据Move到新空间中,再释放旧数据占用的内存。所以很大可能的原因就是两次分配之间的时候,已经用光了进程允许的线性虚拟内存空间了。
 
不明白为什么代码要这样写~~
如果不确定大小,就先分配一个尽量大的数字给他,然后,在循环中计算,如果最后计数超出已分配的大小,则再一次分配固定的大小,如果不超出,则分配计数那样的大小不就ok了吗?
 
楼上,这样写是为了说明问题,另外,只所以不事先分配内存,是因为正在写一个服务程序,该程序可能同时上百人访问,内存非常宝贵,不可能对每个线程都分配足够大的内存,再次,程序的每个线程需要构造容量未知的集合,而且要进行集合的运算。
甚至连Tlist都舍不得用,因为tlist会对每个集合元素多消耗8个字节
 
这是看到的一篇国外的贴子:
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.

The only way to prevent that is to not resize the array in small
increments. 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.
 
把 myarray:array of integer 的声明放到公共全局去就可以避免你遇到的尴尬。

按照你现在的声明情况,默认的,你最多不会超过 1MB 的内存可供这个数组使用,看看代码,就知道会 Out of Memory 了。

因为,目前的声明,这个东西只消耗栈内存。
 
to 小雨哥:
1MB 的内存是栈的默认长度,而setlength是对堆的操作,空间应该是4G吧???
 
后退
顶部