主题:内存的管理(第二节) DATE :2004-09-24
主题:内存的管理(第二节)
时间:9月24日下午3点
主持:A3.武稀松
地点:会议室
2004-09-24 15:02:49 A3.武稀松
好!开课
2004-09-24 15:03:31 英雄莫问出处
老兄,先列个提纲
2004-09-24 15:03:38 A3.武稀松
要讲内存管理显要知道Delphi的数据类型分几种?
2004-09-24 15:03:57 黄
喜欢,
2004-09-24 15:04:02 英雄莫问出处
这个恐怕不要讲了吧?
2004-09-24 15:04:00 B6
基本的吧
2004-09-24 15:04:21 欢乐狗熊
似乎有很多种哦,呵呵
2004-09-24 15:04:22 英雄莫问出处
不是说要讲共享内存的几种方式吗?
2004-09-24 15:04:23 B6
integer,char,^
2004-09-24 15:04:30 B6
record
2004-09-24 15:04:42 B6
string
2004-09-24 15:04:56 飘尘
还有CLASS了
2004-09-24 15:05:06 关艳月
其实,数据就分两种,实型和虚型。
2004-09-24 15:06:13 关艳月
象 pchar ,string, class ,record,array 就是虚型。
2004-09-24 15:06:17 关艳月
对不?
2004-09-24 15:06:24 欢乐狗熊
武松又不说话了
2004-09-24 15:06:25 英雄莫问出处
没错
2004-09-24 15:06:31 飘尘
string 应当是
CHAR的扩展类型
2004-09-24 15:06:40 欢乐狗熊
对
2004-09-24 15:06:48 A3.武稀松
一种是值类型,一种是抽象数据类型
2004-09-24 15:06:56 英雄莫问出处
等到真正定义虚型变量的时候,才分配内存
2004-09-24 15:07:13 B6
重点是内存管理,大家别跑题了
2004-09-24 15:07:36 英雄莫问出处
不是上次已经讲过基本的了?
2004-09-24 15:07:43 A3.武稀松
浮点数、有序数、纪录等都是抽象数据类型
2004-09-24 15:07:58 A3.武稀松
这种类型的内存管理基本我们不用管它
2004-09-24 15:08:03 关艳月
内存的基本类型要认识,这也是内存管理的重要因素啊。
2004-09-24 15:08:37 英雄莫问出处
这次讲讲共享内存的几种方式,比如内存映象文件、线程共享模式等?
2004-09-24 15:08:51 A3.武稀松
关艳月说得对,数据类型先搞清楚才能搞清楚内存管理
2004-09-24 15:09:32 A3.武稀松
另外一种抽象数据类型就是我们要手工分配长度的,例如指针、对象等等
2004-09-24 15:10:14 关艳月
我的做法很简单,所有的数据就分两种,这样最容易懂了。 A1教的。[:D]
2004-09-24 15:10:38 A3.武稀松
你倒是比较会活学活用
2004-09-24 15:11:28 A3.武稀松
其中值类型是由栈来管理的。这样我们就只要关心抽象数据类型就可以了
2004-09-24 15:11:54 た少林足球
这些对我来说太抽象了,听起来不太懂
2004-09-24 15:12:10 A3.武稀松
上次A1讲的银行卡就是我们这次话题的基础
2004-09-24 15:12:29 C03.MUSIC
有没有必要讲讲堆和栈
2004-09-24 15:12:45 た少林足球
那就讲一下
2004-09-24 15:12:49 关艳月
A3,不要把此“抽象”和类的“抽象”混和了,大家会混稍的。
2004-09-24 15:13:33 A3.武稀松
堆栈以后讲。其实Delphi中抽象数据类型也不一定非要我们手工分配和释放。有些编译器会帮我们处理。例如字符串
2004-09-24 15:14:07 关艳月
有两种字符串, string 和 pchar
2004-09-24 15:14:14 A3.武稀松
谁知道字符串的生存周期是怎样的?为什么不需要我们手工干预?
2004-09-24 15:14:48 英雄莫问出处
这是在DELPHI编译器里决定的
2004-09-24 15:15:02 英雄莫问出处
会自动分配和释放,继续
2004-09-24 15:15:14 Ares
有两种字符串, string 和 pchar????
2004-09-24 15:15:15 A3.武稀松
对,但是编译器怎么知道什么时候释放?
2004-09-24 15:15:37 关艳月
你要干预它也可以啊。比如,当用到MoveMemory()的时候。
2004-09-24 15:15:52 A3.武稀松
PChar严格来说是字符指针。Type PChar=Char;
2004-09-24 15:15:59 A3.武稀松
PChar=^Char;
2004-09-24 15:16:20 Ares
movememory和copymemory有什么区别?
2004-09-24 15:16:36 A3.武稀松
字符串和接口、动态数组一样都是通过引用计数器来管理的
2004-09-24 15:17:17 A3.武稀松
引用计数器是垃圾回收中最快捷的一种方式
2004-09-24 15:18:24 关艳月
却是在DLL和EXE沟通中最可恨的方式。别怪我老挑毛病。
2004-09-24 15:18:51 A3.武稀松
也就是说在你赋值的时候他会自动把引用计数加一,表示有一个变量在使用它。当变量销毁或指向别处的时候他会自动把计数减一,如果引用计数为0。就回收这片内存
2004-09-24 15:20:00 A3.武稀松
String的引用计数器我们是不是有必要让她暴露出来看一下她的真面目?
2004-09-24 15:20:33 Ares
如果我手工将计数改了, 会有什么情况?
2004-09-24 15:20:53 关艳月
怕是你好难改吧。
2004-09-24 15:21:07 A3.武稀松
可以改。我来先讲一下字符串的构造。
2004-09-24 15:21:47 A3.武稀松
字符串其实可以看成是一个结构的指针。
2004-09-24 15:22:04 Ares
应该是@S[0] - 4
2004-09-24 15:22:21 A3.武稀松
我自己定义了一个和系统的AnsiString兼容的字符串结构。如下:
_PTAnsiString = ^_TAnsiString;
_TAnsiString = record
allocSiz: LongWord; //分配的大小
ReferencCount: LongWord; //引用次数
Length: LongWord; //字符串长度
Data: array[1..(Length + 1)] of AnsiChar;
end;
2004-09-24 15:23:26 A3.武稀松
可以看到Ares说的减4得到的是字符串的长度位置,而非今天我们要说的计数器位置
2004-09-24 15:24:08 A3.武稀松
计数器应该时减8才对
2004-09-24 15:24:24 A3.武稀松(42088303)
下面我们来证实一下
2004-09-24 15:24:46 Ares(53257667)
总之是那减去longint的长度的整倍数
2004-09-24 15:25:11 A3.武稀松(42088303)
type
_PTAnsiString = ^_TAnsiString;
_TAnsiString = record
allocSiz: LongWord; //分配的大小
ReferencCount: LongWord; //引用次数
Length: LongWord; //字符串长度
//Data: array[1..(Length + 1)] of AnsiChar;
end;
var
k, M, N : AnsiString;
p : _PTAnsiString;
begin
k := 'I am a Delphi fan!';
p := Pointer(Integer(@K[1]) - SizeOf(_TAnsiString));
Showmessage(format('编译器初始化分配给内存大小是:%d'
+ #13 + '引用次数是:%d'
+ #13 + '字符串长度是:%d;'
+ #13 + '字符串内容是:"%s"',
[P^.allocSiz, P^.ReferencCount, P^.Length, K]));
end;
2004-09-24 15:25:19 Ares(53257667)
所以, 如果手工将那改了, 会不会有什么问题
2004-09-24 15:25:54 A3.武稀松(42088303)
大家可以试一下我上面贴的代码
2004-09-24 15:29:18 A3.武稀松(42088303)
我讲到怎么查看字符串的引用计数器
2004-09-24 15:29:33 A3.武稀松(42088303)
procedure TForm1.Button3Click(Sender: TObject);
type
_PTAnsiString = ^_TAnsiString;
_TAnsiString = record
allocSiz: LongWord; //分配的大小
ReferencCount: LongWord; //引用次数
Length: LongWord; //字符串长度
//Data: array[1..(Length + 1)] of AnsiChar;
end;
var
k, M, N : AnsiString;
p : _PTAnsiString;
begin
k := 'I am a Delphi fan!';
p := Pointer(Integer(@K[1]) - SizeOf(_TAnsiString));
Showmessage(format('编译器初始化分配给内存大小是:%d'
+ #13 + '引用次数是:%d'
+ #13 + '字符串长度是:%d;'
+ #13 + '字符串内容是:"%s"',
[P^.allocSiz, P^.ReferencCount, P^.Length, K]));
end;
2004-09-24 15:31:41 TCP/IP INFO(31329846)
我执行了
2004-09-24 15:31:48 A3.武稀松(42088303)
OK。那我们在调整一下
2004-09-24 15:32:13 A3.武稀松(42088303)
type
_PTAnsiString = ^_TAnsiString;
_TAnsiString = record
allocSiz: LongWord; //分配的大小
ReferencCount: LongWord; //引用次数
Length: LongWord; //字符串长度
//Data: array[1..(Length + 1)] of AnsiChar;
end;
var
k, M, N : AnsiString;
p : _PTAnsiString;
begin
k := 'I am a Delphi fan!';
p := Pointer(Integer(@K[1]) - SizeOf(_TAnsiString));
M := K; //把K赋值给M实际上只是把M的指向地址修改为与K相同,并且把引用次数加一
Showmessage(format('编译器初始化分配给内存大小是:%d'
+ #13 + '引用次数是:%d'
+ #13 + '字符串长度是:%d;'
+ #13 + '字符串内容是:"%s"',
[P^.allocSiz, P^.ReferencCount, P^.Length, K]));
end;
2004-09-24 15:32:55 A3.武稀松(42088303)
看看有什么变化
2004-09-24 15:33:28 Ares(53257667)
type
PStrRec = ^StrRec;
StrRec = packed record
refCnt: Longint;
length: Longint;
end;
2004-09-24 15:33:50 欢乐狗熊(228175978)
引用次数加1
2004-09-24 15:34:09 A3.武稀松(42088303)
Ares的是System单元给出的逻辑结构,不是真实的。还有些是他隐藏了的
2004-09-24 15:34:26 Ares(53257667)
不过好象ShortString不是这样的吧
2004-09-24 15:34:39 A3.武稀松(42088303)
procedure TForm1.Button3Click(Sender: TObject);
type
_PTAnsiString = ^_TAnsiString;
_TAnsiString = record
allocSiz: LongWord; //分配的大小
ReferencCount: LongWord; //引用次数
Length: LongWord; //字符串长度
//Data: array[1..(Length + 1)] of AnsiChar;
end;
var
k, M, N : AnsiString;
p : _PTAnsiString;
begin
k := 'I am a Delphi fan!';
p := Pointer(Integer(@K[1]) - SizeOf(_TAnsiString));
M := K; //把K赋值给M实际上只是把M的指向地址修改为与K相同,并且把引用次数加一
M := M + 'A';//把M的内容修改,这时候M和K的内容不同了,就不再用同一个地址
//而这时才为M分配一个新的内存块,把M指向新块,同时M原来的指向引用计数减一
Showmessage(format('编译器初始化分配给内存大小是:%d'
+ #13 + '引用次数是:%d'
+ #13 + '字符串长度是:%d;'
+ #13 + '字符串内容是:"%s"',
[P^.allocSiz, P^.ReferencCount, P^.Length, K]));
end;
2004-09-24 15:34:51 A3.武稀松(42088303)
我说了我演示的是AnsiString
2004-09-24 15:36:03 A3.武稀松(42088303)
procedure TForm1.Button3Click(Sender: TObject);
type
_PTAnsiString = ^_TAnsiString;
_TAnsiString = record
allocSiz: LongWord; //分配的大小
ReferencCount: LongWord; //引用次数
Length: LongWord; //字符串长度
//Data: array[1..(Length + 1)] of AnsiChar;
end;
var
k, M, N : AnsiString;
p : _PTAnsiString;
begin
k := 'I am a Delphi fan!';
p := Pointer(Integer(@K[1]) - SizeOf(_TAnsiString));
M := K; //把K赋值给M实际上只是把M的指向地址修改为与K相同,并且把引用次数加一
M := M + 'A';//把M的内容修改,这时候M和K的内容不同了,就不再用同一个地址
//而这时才为M分配一个新的内存块,把M指向新块,同时M原来的指向引用计数减一
Showmessage(format('编译器初始化分配给内存大小是:%d'
+ #13 + '引用次数是:%d'
+ #13 + '字符串长度是:%d;'
+ #13 + '字符串内容是:"%s"',
[P^.allocSiz, P^.ReferencCount, P^.Length, K]));
end;
2004-09-24 15:37:00 A3.武稀松(42088303)
那么大家对引用计数怎么理解的呢?
2004-09-24 15:37:45 TCP/IP INFO(31329846)
可能和 java 的 string 差不多
2004-09-24 15:37:58 TCP/IP INFO(31329846)
都是静态的吧
2004-09-24 15:38:12 TCP/IP INFO(31329846)
每次都分配
2004-09-24 15:38:17 A3.武稀松(42088303)
Java的垃圾回收比较复杂。Delphi就比较简单
2004-09-24 15:38:20 关艳月(110499998)
别用红色的字!!!
2004-09-24 15:38:24 D10.天地弦(185511468)
_TAnsiString = record
allocSiz: LongWord; //分配的大小
ReferencCount: LongWord; //引用次数
Length: LongWord; //字符串长度
2004-09-24 15:39:01 A3.武稀松(42088303)
D10这是给出的字符串逻辑结构。和系统的ANSIString兼容的
2004-09-24 15:39:42 A3.武稀松(42088303)
垃圾回收有很多种,其中引用计数是最为原始但最有效的。
2004-09-24 15:39:58 A3.武稀松(42088303)
这里的有效是指时间效率
2004-09-24 15:40:59 TCP/IP INFO(31329846)
把M的内容修改,这时候M和K的内容不同了,delphi 怎么实现的
2004-09-24 15:41:42 Ares(53257667)
把M的内容修改,这时候M和K的内容不同了,delphi 怎么实现的?
复制
2004-09-24 15:41:54 A3.武稀松(42088303)
编译器会处理:=这个动作如果内容相同的话就是用同一空间,计数加一。如果内容不同就重新分配空间,原计数器减一
2004-09-24 15:42:46 关艳月(110499998)
我提问:假如: A:='Hello'; B:=A ; C:=A+'' ,这时A的计数是多少?
2004-09-24 15:43:15 A3.武稀松(42088303)
Delphi中动态数组、字符串、接口都是通过计数器来管理的内存的。所以我们不必理会他们。
2004-09-24 15:43:30 A3.武稀松(42088303)
2
2004-09-24 15:44:08 TCP/IP INFO(31329846)
我试了是 2
2004-09-24 15:44:12 C03.MUSIC(281361369)
为什么是2不是3
2004-09-24 15:44:19 A3.武稀松(42088303)
我来解释一下
2004-09-24 15:44:45 Ares(53257667)
var
S : string;
P : ^longInt;
begin
S := 'abcdefg';
P := Pointer(integer(@S[1]) - 4);
showmessage(IntToStr(P^));
P^ := 0;
ShowMessage(S);
end;
为什么显示出来是'a'而不是''
2004-09-24 15:45:20 A3.武稀松(42088303)
A:='Hello';计数器=1
B:=A ; 计数器=2
C:=A+''A所指向字符串的计数器不受影响
2004-09-24 15:45:44 关艳月(110499998)
为什么C不会影响A呢
2004-09-24 15:45:58 D10.天地弦(185511468)
C是另外一个变量了
2004-09-24 15:46:07 A3.武稀松(42088303)
D10说得对
2004-09-24 15:46:15 欢乐狗熊(228175978)
新加了一个字符重新分空间了
2004-09-24 15:46:21 A3.武稀松(42088303)
D10理解了计数器。
2004-09-24 15:46:24 TCP/IP INFO(31329846)
A+''时候,可能系统又分配了空间,让C指向
2004-09-24 15:46:32 A3.武稀松(42088303)
狗熊也明白了
2004-09-24 15:46:41 Ares(53257667)
A3, 帮我结实一下我那结果啊
2004-09-24 15:46:58 A3.武稀松(42088303)
这么多人都懂了,没白费我的口水
2004-09-24 15:48:05 关艳月(110499998)
C:=A+'' 这个''是空的。
2004-09-24 15:48:20 Ares(53257667)
人蠢, 没办法。 小狗狗, 明白了吗?
2004-09-24 15:48:26 A3.武稀松(42088303)
那么我们再讲一下对象的内存管理方式
2004-09-24 15:48:50 D10.天地弦(185511468)
Ares的意思吧,为C分配了另外一个空间。不是引用
2004-09-24 15:49:08 关艳月(110499998)
从意义上来讲 C=A是成立的。
2004-09-24 15:49:50 A3.武稀松(42088303)
但是从编译器看来他不知道内容是否相同啊
2004-09-24 15:49:55 Ares(53257667)
Ares的意思吧,为C分配了另外一个空间。不是引用
我是将字符串长度设置成了0
2004-09-24 15:50:21 A3.武稀松(42088303)
这个话题可以结束了吧。有人不懂就去问D10。[:P]
2004-09-24 15:50:45 D10.天地弦(185511468)
我怕误人子弟
2004-09-24 15:51:00 TCP/IP INFO(31329846)
继续吧
2004-09-24 15:51:10 A3.武稀松(42088303)
大家说对象的内存分配是如何分配的?
2004-09-24 15:51:14 关艳月(110499998)
在DLL和EXE沟通的时候, C:=A+''是非常有意义的。
2004-09-24 15:51:37 关艳月(110499998)
继续,我不打扰了。[;-D]
2004-09-24 15:51:52 D10.天地弦(185511468)
A3是不是就说了这一个?
2004-09-24 15:51:59 D10.天地弦(185511468)
我迟到了
2004-09-24 15:53:06 A3.武稀松(42088303)
D10来的不晚刚刚说一个
2004-09-24 15:53:39 A3.武稀松(42088303)
既然来晚了就罚你说说你对对象的内存分配的理解
2004-09-24 15:54:38 D10.天地弦(185511468)
对象的内存分配。是.....
2004-09-24 15:54:49 D10.天地弦(185511468)
不懂。听课!
2004-09-24 15:55:16 A3.武稀松(42088303)
你平时怎么创建对象的呢
2004-09-24 15:55:31 Ares(53257667)
Create
2004-09-24 15:55:40 D10.天地弦(185511468)
A3 := TA3.Create
2004-09-24 15:55:43 C03.MUSIC(281361369)
好象对象的内存分配已经由DELPHI自己给完成了
2004-09-24 15:55:49 Ares(53257667)
直接调用TClass的Create
2004-09-24 15:55:59 关艳月(110499998)
严格来说。Create不能算是真正的创建。
2004-09-24 15:56:08 TCP/IP INFO(31329846)
newinstance
2004-09-24 15:56:17 B4.松鼠(64652023)
那什么时候创建?
2004-09-24 15:57:05 关艳月(110499998)
指定了Constructor的方法可能不只是Create ,但Delphi只认 Constructor的东西。
2004-09-24 15:57:58 A3.武稀松(42088303)
说得对,其实在编译的时候如果是Constructor方法,在第一个Constructor方法前会插入newinstance
2004-09-24 15:58:17 A3.武稀松(42088303)
我说的第一个是指继承层次上的最后一层
2004-09-24 15:59:06 关艳月(110499998)
学来的知识现炒现卖。[;P]
2004-09-24 16:00:40 关艳月(110499998)
继续。
2004-09-24 16:00:56 D10.天地弦(185511468)
在第一个Constructor方法前会插入newinstance
2004-09-24 16:01:01 A3.武稀松(42088303)
对
2004-09-24 16:01:26 A3.武稀松(42088303)
我们可以做一个实验
2004-09-24 16:01:28 D10.天地弦(185511468)
在第一个Constructor方法前会插入newinstance
我说的第一个是指继承层次上的最后一层
可是还是不懂。我是小学生
2004-09-24 16:01:38 A3.武稀松(42088303)
晕
2004-09-24 16:01:45 TCP/IP INFO(31329846)
是缺省,还是...
2004-09-24 16:01:53 关艳月(110499998)
这个好象之前A1和A2有开课过了。
2004-09-24 16:02:10 A3.武稀松(42088303)
就是说在Inherited它祖先的Create方法的时候不会再调用了
2004-09-24 16:02:11 D10.天地弦(185511468)
A3做实验
2004-09-24 16:02:13 B4.松鼠(64652023)
最后一层是指TObject?
2004-09-24 16:02:48 A3.武稀松(42088303)
type
TTest = class
private
FA: string;
public
class function NewInstance: TObject; override;
end;
2004-09-24 16:03:28 A3.武稀松(42088303)
procedure TTest.FreeInstance;
begin
//CleanupInstance;
//_FreeMem(Self);
FreeMem(Pointer(Self),InstanceSize);
end;
2004-09-24 16:03:39 A3.武稀松(42088303)
搞错了,更正
2004-09-24 16:03:48 A3.武稀松(42088303)
class function TTest.NewInstance: TObject;
var
Instance : Pointer;
begin
//Result := InitInstance(_GetMem(InstanceSize));
GetMem(Instance, InstanceSize);
PInteger(Instance)^ := Integer(Self);
Result := InitInstance(TObject(Instance));
end;
2004-09-24 16:04:35 A3.武稀松(42088303)
class function TTest.NewInstance: TObject;
var
Instance : Pointer;
begin
//Result := InitInstance(_GetMem(InstanceSize));
GetMem(Instance, InstanceSize);
Result := InitInstance(TObject(Instance));
end;
2004-09-24 16:04:42 D10.天地弦(185511468)
A3NewInstance这个方法在哪里调用?
2004-09-24 16:05:02 关艳月(110499998)
Constrcutor之前。
2004-09-24 16:05:03 A3.武稀松(42088303)
在构造函数的最前面
2004-09-24 16:05:23 D10.天地弦(185511468)
是隐藏的?
2004-09-24 16:05:33 A3.武稀松(42088303)
对,由编译器负责
2004-09-24 16:05:46 D10.天地弦(185511468)
哦,你要早说清楚
2004-09-24 16:06:44 A3.武稀松(42088303)
一旦调用过以后他会在DL寄存器上做标记。由此判断,以后的Inherited祖先的构造方法就不会再调用NewInstance了
2004-09-24 16:07:34 D10.天地弦(185511468)
FreeInstance是最后调用的方法?
2004-09-24 16:07:38 A3.武稀松(42088303)
对
2004-09-24 16:07:40 A3.武稀松(42088303)
class function TTest.NewInstance: TObject;
var
Instance : Pointer;
begin
//Result := InitInstance(_GetMem(InstanceSize));
GetMem(Instance, InstanceSize);
Result := InitInstance(TObject(Instance));
end;
2004-09-24 16:07:52 A3.武稀松(42088303)
注释掉的是系统的代码。
2004-09-24 16:08:08 A3.武稀松(42088303)
我用代码解释了一下系统的代码
2004-09-24 16:09:06 C03.MUSIC(281361369)
先分配内存,再初始化实例
2004-09-24 16:09:15 A3.武稀松(42088303)
对的
2004-09-24 16:09:16 关艳月(110499998)
简单是最好的东西,不知能不能用简单的方式来说明这个东西。
2004-09-24 16:09:48 C03.MUSIC(281361369)
实例都已经初始化了,那CREATE是干什么用的?
2004-09-24 16:10:04 D10.天地弦(185511468)
做要做的事
2004-09-24 16:10:16 A3.武稀松(42088303)
InitInstance中会自动把内存全部清零。这就是为什么我们的对象中的Integer会是0,字符串会是空
2004-09-24 16:10:44 A3.武稀松(42088303)
Create主要是让你来初始化对象的
2004-09-24 16:11:05 D10.天地弦(185511468)
看看Create的源码就知道了
2004-09-24 16:11:13 Ares(53257667)
initinstance是怎么样的代码
2004-09-24 16:11:25 D10.天地弦(185511468)
var
IntfTable: PInterfaceTable;
ClassPtr: TClass;
I: Integer;
begin
FillChar(Instance^, InstanceSize, 0);
PInteger(Instance)^ := Integer(Self);
ClassPtr := Self;
while ClassPtr <> nil do
begin
IntfTable := ClassPtr.GetInterfaceTable;
if IntfTable <> nil then
for I := 0 to IntfTable.EntryCount-1 do
with IntfTable.Entries[I] do
begin
if VTable <> nil then
PInteger(@PChar(Instance)[IOffset])^ := Integer(VTable);
end;
ClassPtr := ClassPtr.ClassParent;
end;
Result := Instance;
2004-09-24 16:11:51 A3.武稀松(42088303)
谢谢,我不用找代码了
FillChar(Instance^, InstanceSize, 0);就是我说的那一句清零动作
2004-09-24 16:12:21 Ares(53257667)
FillMemory还是fillchar
2004-09-24 16:12:32 A3.武稀松(42088303)
效果一样
2004-09-24 16:12:41 Ares(53257667)
fillchar能用0来做参数吗
2004-09-24 16:13:09 Ares(53257667)
错了, 确实是0
2004-09-24 16:13:34 ★hotdog★(278136300)
0是不是有特殊的含义阿
2004-09-24 16:13:52 Ares(53257667)
fillmemory是不是内部有循环的代码啊
2004-09-24 16:14:05 D10.天地弦(185511468)
插一句小学生的问题构造函数可以不用Create是吗?
construtor selfcreate()也可以是吗?
2004-09-24 16:14:09 A3.武稀松(42088303)
PInteger(Instance)^ := Integer(Self);实例的类的信息其实
2004-09-24 16:14:24 C03.MUSIC(281361369)
TO D10:
可以
2004-09-24 16:14:26 关艳月(110499998)
to D10,小学生也知道可以。
2004-09-24 16:14:36 A3.武稀松(42088303)
构造方法名字随便他只认construtor关键字
2004-09-24 16:15:00 Ares(53257667)
我现在想知道TClass中类型信息放在什么地方
2004-09-24 16:15:00 D10.天地弦(185511468)
呵呵,我是只学了两个月的学前班。A1说的。所以不要见怪。
2004-09-24 16:15:31 D10.天地弦(185511468)
TClass = class of TObject;
2004-09-24 16:15:32 A3.武稀松(42088303)
while ClassPtr <> nil do
begin
IntfTable := ClassPtr.GetInterfaceTable;
if IntfTable <> nil then
for I := 0 to IntfTable.EntryCount-1 do
with IntfTable.Entries[I] do
begin
if VTable <> nil then
PInteger(@PChar(Instance)[IOffset])^ := Integer(VTable);
end;
这一段是实现对象和接口的绑定
2004-09-24 16:15:34 Ares(53257667)
A3, 说说这方面的吧, 你说的哪内存分配没意思
2004-09-24 16:16:54 A3.武稀松(42088303)
其实我们都研究到了这种地步内存分配也没什么神秘的了
2004-09-24 16:17:08 D10.天地弦(185511468)
没有神秘好啊
2004-09-24 16:17:31 C03.MUSIC(281361369)
DELPHI的内存分配代码是不是汇编实现的
2004-09-24 16:18:07 A3.武稀松(42088303)
其实内存管理还有一点,万变不离其宗只要不是API分配的内存,不管什么方法都回落到GetMem上
2004-09-24 16:19:06 A3.武稀松(42088303)
New,AllocMem不管怎么样最后都要落在GetMem上。API除外
2004-09-24 16:20:08 关艳月(110499998)
A3,我建议换个方式来讲。[:)]
2004-09-24 16:20:09 A3.武稀松(42088303)
如果时间还够的话可以讲内存管理器。
2004-09-24 16:20:20 D10.天地弦(185511468)
好好,讲内存管理器
2004-09-24 16:20:21 A3.武稀松(42088303)
关艳月什么方式呢?
2004-09-24 16:20:46 关艳月(110499998)
比如,从技巧上来讲。
2004-09-24 16:21:01 关艳月(110499998)
例如,
2004-09-24 16:21:54 A3.武稀松(42088303)
我觉得有了这些较为基础的知识,技巧只是思考和经验的结果。这些基础的知识是本,技巧是末。不知关艳月如何认为?
2004-09-24 16:22:13 关艳月(110499998)
A是一个64KB的字符串,B要取得A前面的32KB,什么方式最好?也是内存管理问题。
2004-09-24 16:22:13 D10.天地弦(185511468)
A3讲内存管理器吧
2004-09-24 16:22:34 Ares(53257667)
A是一个64KB的字符串,B要取得A前面的32KB,什么方式最好?也是内存管理问题。
说说
2004-09-24 16:23:03 A3.武稀松(42088303)
我不想解决这些问题。我们可以以后私聊解决
2004-09-24 16:23:22 A3.武稀松(42088303)
我就讲内存管理器的知识了
2004-09-24 16:23:41 关艳月(110499998)
那好,我再问一个内存管理器的问题。
2004-09-24 16:24:06 A3.武稀松(42088303)
能开Delphi的就打开System单元,我们对照着讲比较方便
2004-09-24 16:24:28 A3.武稀松(42088303)
其实这里比较简单。
2004-09-24 16:24:58 A3.武稀松(42088303)
看这里
PMemoryManager = ^TMemoryManager;
TMemoryManager = record
GetMem: function(Size: Integer): Pointer;
FreeMem: function(P: Pointer): Integer;
ReallocMem: function(P: Pointer; Size: Integer): Pointer;
end;
2004-09-24 16:25:06 关艳月(110499998)
如何改造一个内存管理器,使得让Object的所申请的内存是全局的。
2004-09-24 16:25:27 D10.天地弦(185511468)
这个属于和A3私聊的问题
2004-09-24 16:26:12 A3.武稀松(42088303)
系统会创建一个默认的内存管理器。只要不是API分配内存,就一定会落在这个内存管理器的GetMem方法上
2004-09-24 16:26:41 D10.天地弦(185511468)
在什么时候创建
2004-09-24 16:27:03 A3.武稀松(42088303)
var
MemoryManager: TMemoryManager = (
GetMem: SysGetMem;
FreeMem: SysFreeMem;
ReallocMem: SysReallocMem);
这是系统默认的内存管理器
2004-09-24 16:27:35 A3.武稀松(42088303)
全局变量可以直接付初始值
2004-09-24 16:27:54 D10.天地弦(185511468)
举例
2004-09-24 16:28:04 A3.武稀松(42088303)
例如
2004-09-24 16:29:11 A3.武稀松(42088303)
当我们创建一个对象的时候刚才我们说了NewInstance里面用到了_GetMem,所以也落到了MemoryManager的GetMem方法上了
2004-09-24 16:29:43 A3.武稀松(42088303)
如果我们自己接管了MemoryManager,我们就可以知道全部VCL的内存分配和释放了
2004-09-24 16:29:46 Ares(53257667)
全局变量可以直接付初始值?
var
Form1: TForm1 = TForm1.Create(nil);
怎么通过不了?
2004-09-24 16:30:10 D10.天地弦(185511468)
没有老爸
2004-09-24 16:30:24 D10.天地弦(185511468)
怎么创建Form
2004-09-24 16:30:32 D10.天地弦(185511468)
你要掉在空中啊
2004-09-24 16:31:14 A3.武稀松(42088303)
procedure GetMemoryManager(var MemMgr: TMemoryManager);
procedure SetMemoryManager(const MemMgr: TMemoryManager);
function IsMemoryManagerSet: Boolean;
看到了吧
2004-09-24 16:31:34 D10.天地弦(185511468)
OK
2004-09-24 16:32:14 C06.文(4184443)
procedure GetMemoryManager(var MemMgr: TMemoryManager);
begin
MemMgr := MemoryManager;
end;
???
2004-09-24 16:32:23 A3.武稀松(42088303)
我们可以用GetMemoryManager取道系统默认的内存管理器,用SetMemoryManager分配我们自己的管理器。
2004-09-24 16:33:05 D10.天地弦(185511468)
全局函数
2004-09-24 16:33:35 D10.天地弦(185511468)
MemoryManager是个全局变量吧
2004-09-24 16:33:45 A3.武稀松(42088303)
这样我们就可以监视VCL中的内存分配和销毁了。很多VCL的内存泄漏监视工具都是用接管MemoryManager来实现的
2004-09-24 16:33:56 D10.天地弦(185511468)
直接使用不就行了,还要用GetMemoryManager来取?
2004-09-24 16:34:53 A3.武稀松(42088303)
你调用完了你自己的GetMem在最后一行最好调用一下原有的管理器的Getmem
2004-09-24 16:35:16 A3.武稀松(42088303)
有点类似于Hook技术
2004-09-24 16:36:10 A3.武稀松(42088303)
Hook,钩子也,接管原有功能。
2004-09-24 16:36:18 C06.文(4184443)
建议哪位老大有空可以讲讲!
2004-09-24 16:37:03 TCP/IP INFO(31329846)
继续讲呀
2004-09-24 16:37:08 A3.武稀松(42088303)
我只是把一些概念介绍给大家。具体如何灵活的的糟蹋,蹂躏Delphi的内存还要大加利用这些知识自己去捉摸
2004-09-24 16:38:39 Ares(53257667)
A3, 给我们讲讲VMT吧
2004-09-24 16:38:55 D10.天地弦(185511468)
A3这个讲完了?
2004-09-24 16:38:55 A3.武稀松(42088303)
所以我不想决绝问题,只是把最基本的概念介绍一下。以后大家自己发挥了。
遗漏的和错误的概念等A1兄回来补充。
下课啦[v]
2004-09-24 16:38:57 英雄莫问出处(28922297)
虚拟方法表
2004-09-24 16:38:58 C03.MUSIC(281361369)
内存管理器就这些吗?
2004-09-24 16:39:13 ~云淡风轻~(151367466)
虚拟方法表我懂
2004-09-24 16:39:16 ~云淡风轻~(151367466)
哈哈
2004-09-24 16:39:21 C06.文(4184443)
那你说说!
2004-09-24 16:39:23 英雄莫问出处(28922297)
今天到此为止?
2004-09-24 16:39:24 Ares(53257667)
赶快去嘘嘘
2004-09-24 16:39:26 B3.Locet(2212967)
那你也说说VMT~~云妹妹`
2004-09-24 16:39:49 ~云淡风轻~(151367466)
自己看书
2004-09-24 16:39:54 B3.Locet(2212967)
看样子你掌握的不够
2004-09-24 16:39:55 ~云淡风轻~(151367466)
开发人员指南里面有
2004-09-24 16:40:00 ~云淡风轻~(151367466)
就几句
2004-09-24 16:40:35 ★hotdog★(278136300)
指针和对象是需要程序员手工申请和释放的内存。
指针包括PChar、Pointer(无类型指针)、记录指针、变量指针(指向原子变量)、函数指针(例如回调函数,分为全局函数和对象方法)。使用New函数来申请内存,使用Dispose来释放指针。另外,GetMem、ReallocMem和FreeMem也是一系列申请、释放内存的函数,可以通过GetMemoryManager和SetMemoryManager函数来读取和设置Delphi的三个内存管理函数。
2004-09-24 16:41:00 Ares(53257667)
inside VCL是李维的书吧
2004-09-24 16:42:51 D10.天地弦(185511468)
A3回来没有
2004-09-24 16:45:40 A3.武稀松(42088303)
福州人很讨厌 ?地方歧视吧
2004-09-24 16:45:41 D10.天地弦(185511468)
不是
2004-09-24 16:47:10 D10.天地弦(185511468)
还有两个问题等你回答
2004-09-24 16:48:07 D10.天地弦(185511468)
185511468(D10.天地弦) 16:35:01
MemoryManager是个全局变量吧
直接使用不就行了,还要用GetMemoryManager来取?
2004-09-24 16:48:58 C03.MUSIC(281361369)
NOT BBB = PPP
2004-09-24 16:49:31 D10.天地弦(185511468)
A3
2004-09-24 16:51:12 A3.武稀松(42088303)
他既然这么提供我们就这么用呗。那Borland没规定你的构造函数必须要用Create我们咋都用Create命名呢
2004-09-24 16:51:26 D10.天地弦(185511468)
哦。
[闲聊中....]
2004-09-24 16:55:42 A1.Aleyn.wu(45198124)
DLL和EXE,开始了。
2004-09-24 16:55:58 A1.Aleyn.wu(45198124)
跟内存管理有关。
2004-09-24 16:56:49 A1.Aleyn.wu(45198124)
头痛的事情好多,我先放松一下,给大家一个小技巧。
2004-09-24 16:57:38 A1.Aleyn.wu(45198124)
大家可以一起做个实验。
2004-09-24 16:59:14 A1.Aleyn.wu(45198124)
在EXE中,var a:string
2004-09-24 16:59:31 A1.Aleyn.wu(45198124)
然后 a:='hello';
2004-09-24 16:59:53 A1.Aleyn.wu(45198124)
在DLL中,b:=a
2004-09-24 17:00:01 A1.Aleyn.wu(45198124)
并showmessage(b)
2004-09-24 17:00:35 TCP/IP INFO(31329846)
我试过,不行,可能有问题
2004-09-24 17:00:40 A3.武稀松(42088303)
a要是全局变量应该正常吧
2004-09-24 17:00:57 飘尘(43745429)
也不对吧
2004-09-24 17:01:11 A1.Aleyn.wu(45198124)
从最简单的来,A假设是全局的。
2004-09-24 17:01:11 飘尘(43745429)
要是有两个程序在调用A了
2004-09-24 17:01:39 A3.武稀松(42088303)
A1有没有试过a是全局变量吧
2004-09-24 17:01:49 A1.Aleyn.wu(45198124)
呵呵,都有试过。
2004-09-24 17:02:00 A3.武稀松(42088303)
和局部变量一样?
2004-09-24 17:02:06 飘尘(43745429)
写两个程序
2004-09-24 17:02:23 飘尘(43745429)
一起调用那个DLL
2004-09-24 17:02:37 A1.Aleyn.wu(45198124)
这不是最重要的问题。
2004-09-24 17:02:43 Ares(53257667)
使用了ShareMem单元没
2004-09-24 17:02:52 A1.Aleyn.wu(45198124)
不使用。
2004-09-24 17:03:11 Ares(53257667)
不使用恐怕不是很好吧
2004-09-24 17:03:19 A3.武稀松(42088303)
我最喜欢DLL和EXE都带包与行了,啥麻烦事都没有了
2004-09-24 17:03:40 A1.Aleyn.wu(45198124)
使用了就不谈今天的这个技巧了。
2004-09-24 17:04:10 A3.武稀松(42088303)
看来比较有意思,看A1笑得那么开心
2004-09-24 17:04:59 A1.Aleyn.wu(45198124)
上面是正常的。
2004-09-24 17:05:14 D10.天地弦(185511468)
出错是正常的?
2004-09-24 17:05:15 A1.Aleyn.wu(45198124)
我们要做的不是这些,这只是测试。
2004-09-24 17:06:00 A1.Aleyn.wu(45198124)
再来,我们在DLL中,a:='hello'+' who are you'
2004-09-24 17:06:29 A1.Aleyn.wu(45198124)
再到EXE中。ShowMessage(a),这时,正常吗?
2004-09-24 17:07:16 A3.武稀松(42088303)
按我说的技巧,EXE和DLL都带包。就啥问题都没有了
2004-09-24 17:07:55 A1.Aleyn.wu(45198124)
A3兄,不是每个程序都要做成包的型式,要不尾巴太大了。
2004-09-24 17:08:19 D10.天地弦(185511468)
A3你包全带?
2004-09-24 17:08:34 A3.武稀松(42088303)
可是如果EXE和DLL共享包总体积反而会小
2004-09-24 17:08:44 Ares(53257667)
按我说的技巧,EXE和DLL都带包。就啥问题都没有了
还不如全部用包算了
2004-09-24 17:09:05 A3.武稀松(42088303)
只要带VCL,RTL包就可以了
2004-09-24 17:09:17 A1.Aleyn.wu(45198124)
算了,还是找个时间写个DEMO。要不难讲。
2004-09-24 17:10:05 D10.天地弦(185511468)
A1我帮你写好了一部分Demo
2004-09-24 17:10:08 A3.武稀松(42088303)
DLL和EXE之间用String本来就是危险的嘛
2004-09-24 17:10:23 D10.天地弦(185511468)
A1我测试怎么没有问题
2004-09-24 17:10:31 D10.天地弦(185511468)
var
a: string;
DLLHandle: Thandle;
DLLSub: procedure(Astr: string);
begin
a := 'Delphi';
DLLhandle := LoadLibrary('ADLL.DLL');
@DLLSub := GetProcAddress(DLLHandle, 'TestDLL');
DLLSub(a);
2004-09-24 17:10:34 Ares(53257667)
DLL和EXE之间用String本来就是危险的嘛
我们没有传任何string
2004-09-24 17:10:40 D10.天地弦(185511468)
没有错误出现
2004-09-24 17:12:51 A1.Aleyn.wu(45198124)
to D10, 我写个DEMO,你就知道错误在什么地方出现了,就象上次的DEMO一样。
[没有正事说了,A1 Demoing 其他人谈论怎么泡MM中...]