谁对tlist有兴趣(50分)

  • 主题发起人 主题发起人 lhdqz
  • 开始时间 开始时间
L

lhdqz

Unregistered / Unconfirmed
GUEST, unregistred user!
tlist 中放成千上万个对象,发现数据混乱,是内存用完了引起的吗?
 
在线请说话,最好贴代码出来,关键赋值与取用的就可以了
 
tlist 只是用来存放指针的,一个指针才占4个字节,你看看你的程序在运行时占用多少内存,不知道你所说的数据混乱是什么意思。
 
哈哈又是japhe,你试着用这个程序:
type
Pmyrec = ^Tmyrec;
Tmyrec = record
x : array[0..65535] of char;
y : longword;
end;

procedure filllist;
var
i : integer;
myrec : pmyrec;
alist :Tlist;
begin
alist := Tlist.create;
for i := 0 to 65535do
begin
new(myrec);
strpcopy(myrec^.x,inttostr);
myrec^.y := i;
alist.add(myrec);

end;


end;

看看占多少内存
 
看看tlist源码,实际上是一个指针书组而已。只不过需要的时候分配内存。tlist并不是无限制使用,而是有个限制,具体多少,你翻看tlist源码就知道了。如果超过这个界限,一定会发生内存混乱的。
 
procedure TForm1.FormCreate(Sender: TObject);
var
TestList : Tlist;
i:word;
begin
TestList := Tlist.Create ;
i := 1;
while i>0do
begin
TestList.add(pointer(i));
inc(i);
end;
showmessage(inttostr(Testlist.Count));
end;
 
Tlist上限是超过65536的,从数据类型上只有longword和integer,通常认为不可能是integer
因为它不可能是负数,只可是无符号整数,估计应该是longword,所以区区几万条记录不足让它占满,我给出的代码实际占有了4*32767个字节的内存,我最先给的代码是为了演示记录所占用的内存,只是跟japhe开个玩笑而已,Tlist确实只是定义一个longword这样无符号整型指针,这也是跟windows的内存管理相对应的,一个进程的最大寻址空间就是longword的上限,而有理由相应Tlist本身也是的上限就是4294967296.如有别的问题请继续.
 
应该是吧
 
procedure TForm1.Button1Click(Sender: TObject);
var
TestList : Tlist;
i,j:word;
begin
TestList := Tlist.Create ;
for j := 1 to 256do
begin
i := 1;
while i>0do
begin
TestList.add(pointer(i*j));
inc(i);
end;
end;
showmessage('数组上限:'+inttostr(Testlist.count)+','+'最后一个值'+inttostr(integer(TestList[TestList.count-1])));
end;
访问第16776960个记录,其值为16776960,指针不会出错,一切正常这可比成千上万条记录多得多.为了验证是不是巧合你可以把j变为0到255,那样值比记录数小.
 
现在还有一个问题,呵
在tLIST
 
不好意思压了个TAB和ENTER就这样了
在TList中我随机类型插入不同的记录如:
PStudent = ^TStudent;
TStudent = packed record
name : string[32];
grade : byte;
end;

PWorker = ^TWorker;
TWorker = packed record
name : string[32];
job : string[10];
end;
--------------------------------
var
AWorker : PWorker;
AStudent : PStudent;
bh : string;
begin
new(AWorker);
bh := inttostr(newid);
AWorker^.name := '1000';
AWorker^.job := 'job' + bh;
myList.Add(AWorker);
dispose(Aworker);
new(AStudent);
bh := inttostr(newid);
AStudent^.name := '2000' ;
AStudent^.grade := newid;
myList.Add(AStudent);
dispose(AStudent);
end;
在使用的时间我怎么分出是哪个记录类型??
 
楼上的代码在.net下是无法通过的,为了将来,最好习惯放弃这种编写方法
 
你意思是在DELPHI.NET下无法通过?
 
建议用class代替record
另外,
myList.Add(AWorker);
dispose(Aworker);

myList.Add(AStudent);
dispose(AStudent);
应该是错误的。myList只是保存指针。你把指针ADD进List里后又把指针指向的记录实体dispose了,这样myList里的指针其实指向了一块赋了初值但没有向系统申请保护,随时会被覆盖的内存。
 
是在D2005/D2006的.net,不支持地址指针,要变通地写,比如用数组或者转换等,
很麻烦,程序结构改变,速度变慢,但始终要适应过来的,微软未来铁定要内置.net
进Windows了。
 
呵呵,kidneyball我把dispose取掉得了,主要是想知道如何分拣出来不同的记录,于至于.net不支持我也考虑以后不用这种办法但现在就此我问题我想知道怎么做.
 
就是这样吗通过classname来区分然后再TWorker(mylist[x])或者TStudent(mylist[x])一次??我实验是通过了感觉有点笨有没有更好的办法呢
type
TStudent = class
name : string[32];
grade : byte;
end;

TWorker = class
name : string[32];
job : string[10];
end;
var
Form1: TForm1;
mylist :Tlist;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
Astudent : TStudent;
AWorker : TWorker;
begin
AStudent := TStudent.Create ;
AStudent.name := 's0000';
AStudent.grade := 1;
mylist.Add(AStudent);
AWorker := TWorker.Create ;
AWorker.name := 'w0000';
AWorker.job := 'job';
mylist.Add(AWorker);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
mylist := tlist.Create ;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
mylist.free;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
edit1.Text := TObject(mylist[spinedit1.Value]).classname;
end;
 
myRecord = packed record
name : string[32];
grade : byte;
end;
TStudent = class
name : string[32];
grade : byte;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
Astudent : TStudent;
arecord : myrecord;//
begin
showmessage(inttostr(sizeof(arecord))+','+inttostr(Astudent.InstanceSize));
end;

结果是34,536 ;;;;;;另外, sizeof(Astudent)返回四,表示其是一个四字节的指针.
问题是我现在要用到SOCKET通讯中,RECV的使用要求每次指定返回字节数,
class的定义会引入Tobject定义的其它部分的字节数,而我要的是实际的记录占用的字节数.其实现在问题就在于怎么分开不同的记录类型,我试验了,实在没试出来。
 
解决办法,如下。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Spin;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
SpinEdit1: TSpinEdit;
Edit2: TEdit;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

const
REC_STUDENT = $80000001;
REC_WORKER = $80000002;
type
PRecHead = ^TRecHead;
TRecHead = packed record
RecType : longword;
end;

pStudent_Body = ^Tstudent_Body;
TStudent_Body = packed record
name : string[32];
grade : byte;
end;
PStudent = ^TStudent;
TStudent = packed record
head : TRecHead;
body : TStudent_body;
end;

pWorker_Body = ^TWorker_Body ;
TWorker_Body = packed record
name : string[32];
job : string[10];
end;
PWorker = ^TWorker;
TWorker = packed record
head : TRecHead;
body : TWorker_body;
end;

var
Form1: TForm1;
mylist :Tlist;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
Astudent : pStudent;
AWorker : pWorker;
begin
new(AStudent) ;
AStudent.head.RecType := REC_STUDENT;
AStudent.body.name := 's0000';
AStudent.body.grade := 1;
mylist.Add(AStudent);
new(AWorker) ;
AWorker.head.RecType := REC_WORKER;
AWorker.body.name := 'w0000';
AWorker.body.job := 'job';
mylist.Add(AWorker);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
mylist := tlist.Create ;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
mylist.free;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
RecType : longword;
begin
RecType := PRecHead(mylist[spinedit1.Value]).rectype;
case RECtype of
$80000001 : begin
edit1.text := PStudent(mylist[spinedit1.Value]).body.name;
edit2.text := inttostr(PStudent(mylist[spinedit1.Value]).body.grade);
end;
$80000002 : begin
edit1.text := PWorker(mylist[spinedit1.Value]).body.name;
edit2.text := PWorker(mylist[spinedit1.Value]).body.job;
end;
end;
end;

end.
 
程序我没留意看。如果一定要用record的话,就要再加入一个外层的record,至少包括两项信息:1是内部record的类型标志,2是内部record的指针。内部record才是实际的记录。
这样,外部引用时只引用外层record. 你再提供一些函数,根据类型标志来强制类型转换内部指针类型。当然也应提供相应过程来new与dispose外层变量(同时new与dispose内层变量并设置类型标志)。并且告诉其他合作编程的人不要直接操作外层record,而应该使用你提供的函数来操作。——现在你就该开始怀念面向对象的封装了。。。。
 
后退
顶部