文档章节

使用多窗体时, 关于节约内存和加快启动速度的思考与尝试

涂孟超
 涂孟超
发布于 2014/09/26 15:34
字数 990
阅读 5
收藏 0
点赞 0
评论 0

刚接触 Delphi 时, 曾以为 Pi 是个常量; 当我知道它是个函数时, 曾被触动.

但 Pi 返回的不过是占 10 个字节的 Extended 类型, 后来竟发现一些对象也这样干, 譬如:
function Clipboard: TClipboard;                       { Clipbrd }
function Printer: TPrinter;                           { Printers }
function Languages: TLanguages;                       { SysUtils }
function RootSprigList: TRootSprigList;               { TreeIntf }
function ComClassManager: TComClassManager;           { ComObj }
function ThemeServices: TThemeServices;               { Themes }
function PropertyCategoryList: TPropertyCategoryList; { PropertyCategories }

//这或许已是 Delphi 2010 中类似对象的全部.

 
 
 
 
 

 

 

  

特别是其中常用的 Clipboard、Printer、Languages, 无需建立就可以像对象一样使用它们.

这是怎么实现的呢? 查看源码, 它们都有类似的结构脉络(以 Clipboard 对象为例):
interface
...
function Clipboard: TClipboard; { 这一般在 interface 的尾部 }
...
implementation
...
var
  FClipboard: TClipboard; { 句柄变量 }
...
function Clipboard: TClipboard; { 函数实现 }
begin
  if FClipboard = nil then
    FClipboard := TClipboard.Create;
  Result := FClipboard;
end;
...

 
 
 
 
 

 

 

  

当然它们还有个释放的问题, 但我觉得这些对象往往也是它所在的单元也在频繁地使用, 一般到最后释放.

它们巧妙的是:
在我们不使用时, 它们并没有建立;
有使用时立即建立;
再使用时也不会重复建立.

真是非常简单而巧妙的思路!

不能不提另外两个相似的对象:
Application {Forms.TApplication}
Screen      {Forms.TScreen}

//这个两个更常用, 但它们不是函数, 的确是对象变量; 它们是在程序生存期一直存在的.

 
 
 
 
 

 

 

  

当一个工程有多个窗体时(恐怕单窗体的程序很少), 那些副窗体能否动态建立呢? 这样做肯定会节约资源、加快启动速度, 我想这无须测试.

上面的做法给了我们很好的借鉴, 不过我想到了两种方法: 1、动态建立; 2、像上面一样通过函数建立.

不管用哪种方法, 都先要禁止程序默认的对窗体的自动建立, 修改如图:



当然也可以直接从工程文件中删除相关的建立代码.

//此时, 我们已经不能使用如下代码打开窗体了:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.Show; { 这会出错, 因为此时 Form2 还没有建立 }
end;

//可以这样:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Application);
  Form2.Show;
end;

//但如果想上面这样, Form2 之后又驻留内存了, 怎么释放它呢? 难道要和 Application 一起释放吗?
//我们的目的是节约内存, 能不能这样?:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Application);
  Form2.Show; { 但 Form2.ShowModal; 可以 }
  Form2.Free;
end;

//尝试上面的代码, 窗体刚刚显示就被释放了, 此路不通!
//还是有解决方案的, 在 Form2 的 OnClose 事件中写点代码:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  { caNone, caHide, caFree, caMinimize 分别是: 取消、隐藏、释放、最小化 }
end;

//这样 Form1 中的调用代码也可以简化如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
  with TForm2.Create(nil) do Show;
end;

 
 
 
 
 

 

 

  

这是第一方案, 第二方案准备学习使用前面提到的 Clipboard 等设计手法.

模仿 Clipboard 的实现, 我们可以把 Form2 所在的 Unit2 单元改写为:
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm2 = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  end;

function Form2: TForm2;

implementation

{$R *.dfm}

var
  FForm: TForm2;

function Form2: TForm2;
begin
  if FForm = nil then
    FForm := TForm2.Create(Application);
  Result := FForm;
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

end.

 
 
 
 
 

 

 

  

这里的窗体和 Clipboard 还是有区别, 因为我们在用完以后要马上释放, 所以代码可以简化为:
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm2 = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  end;

function Form2: TForm2;

implementation

{$R *.dfm}

function Form2: TForm2;
begin
  Result := TForm2.Create(nil);
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

end.

 
 
 
 
 

 

 

  

这样我们在主窗体又可以这样调用了:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.Show;
end;

{ 这和 Delphi 默认的区别可大了, 这里的 Form2 是个函数; 动态建立、动态释放 }

 
 
 
 
 

 

 

  

本文转载自:http://www.cnblogs.com/del/archive/2010/01/19/1651483.html

共有 人打赏支持
涂孟超
粉丝 12
博文 2004
码字总数 14107
作品 0
深圳
程序员
服务器中加速BIOS启动的方法

对于用于一线的主服务器而言,年均宕机时间是衡量其稳定性的重要指标。因此,系统出现故障后,能够尽快恢复尤其重要。在现在的高端服务器中,CPU有多个,内存容量日益增加,有的多达512G甚至...

技术小甜
2017/11/23
0
0
某虚拟化项目总结:一条光纤引发的故障

摘要:在今年9月份的一个虚拟化项目中,项目前期一切正常。在为服务器添加、更换内存之后,出现ESXi主机存储断开、虚拟机系统慢、ESXi主机启动慢的故障,经过多方检查,终于排查了故障。最终...

王春海
06/29
0
0
Pholcus 1.2 发布,高并发、分布式爬虫软件

Pholcus爬虫软件发布1.2版本,CPU使用率与内存占用均有大幅降低,运行更加稳定流畅。同时新增kafka输出方式,加快任务终止速度(秒级延时)。 Pholcus v1.2 具体更新细节如下: 一、输出功能...

henrylee2cn
2016/09/26
1K
7
android 使用双缓冲辨析及surfaceview使用例程-转载(觉得写的很清楚)

本文转自:http://blog.csdn.net/blogercn/article/details/7404485 感谢作者分享! 双缓冲是图像编程中很重要的概念,在电脑的图像处理中就常常使用双缓冲来加快图像显示速度,消除图像刷新...

LiangX
2013/05/28
0
0
一些关于加速Gradle构建的个人经验

目前绝大多数的Android项目都是基于Grale了,因为Gradle确实给我们带来了很多便利,然而,在使用了Gradle后,最大的不满就是编译起来太慢了。解决慢的问题无非有两种方法 提升硬件配置,选择...

技术小黑屋
2017/04/16
0
0
Protobuf使用不当导致的程序内存上涨问题

protocol buffers[1]是google提供的一种将结构化数据进行序列化和反序列化的方法,其优点是语言中立,平台中立,可扩展性好,目前在google内部大量用于数据存储,通讯协议等方面。PB在功能上...

百度MTC
2016/01/11
92
0
用 Web 技术写 Native 应用的框架--MEngine

MEngine 项目定位:使用Web技术写Native应用,更接近原生体验,简单容易上手,能快速开发小型应用,典型的Hybrid应用框架。 为更接近Native应用体验,为此做了一些新的尝试(对比PhoneGap),...

大海月升
2017/06/12
189
0
大海月升/MEngine

MEngine 项目定位:使用Web技术写Native应用,更接近原生体验,简单容易上手,能快速开发小型应用,典型的Hybrid应用框架。 为更接近Native应用体验,为此做了一些新的尝试(对比PhoneGap),...

大海月升
2017/06/15
0
0
高性能队列 Disruptor

偶然中看到一篇 关于disruptor的分析,高性能低延迟的特性吸引了我。 disruptor java实现的线程间通信的高性能低延迟消息组件,也就是消息队列,相比于BlockingQueue 最大的特点在于无锁的机...

ovirtKg
2016/12/15
17
0
简单说一下,你对CPU缓存的了解?

cpu缓存是位于cpu和内存之间的高速缓冲存储器,因为现在cpu的运算速度远远超过了内存的读写速度,因此设置cpu缓存来提高cpu的执行效率。目前主流的cpu存在三级缓存L1,L2,L3缓存,其中每个核...

nj-zhangmq
2016/12/02
17
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

32.filter表案例 nat表应用 (iptables)

10.15 iptables filter表案例 10.16/10.17/10.18 iptables nat表应用 10.15 iptables filter表案例: ~1. 写一个具体的iptables小案例,需求是把80端口、22端口、21 端口放行。但是,22端口我...

王鑫linux
今天
0
0
shell中的函数&shell中的数组&告警系统需求分析

20.16/20.17 shell中的函数 20.18 shell中的数组 20.19 告警系统需求分析

影夜Linux
今天
0
0
Linux网络基础、Linux防火墙

Linux网络基础 ip addr 命令 :查看网口信息 ifconfig命令:查看网口信息,要比ip addr更明了一些 centos 7默认没安装ifconfig命令,可以使用yum install -y net-tools命令来安装。 ifconfig...

李超小牛子
今天
1
0
[机器学习]回归--Decision Tree Regression

CART决策树又称分类回归树,当数据集的因变量为连续性数值时,该树算法就是一个回归树,可以用叶节点观察的均值作为预测值;当数据集的因变量为离散型数值时,该树算法就是一个分类树,可以很...

wangxuwei
昨天
1
0
Redis做分布式无锁CAS的问题

因为Redis本身是单线程的,具备原子性,所以可以用来做分布式无锁的操作,但会有一点小问题。 public interface OrderService { public String getOrderNo();} public class OrderRe...

算法之名
昨天
9
0
143. Reorder List - LeetCode

Question 143. Reorder List Solution 题目大意:给一个链表,将这个列表分成前后两部分,后半部分反转,再将这两分链表的节点交替连接成一个新的链表 思路 :先将链表分成前后两部分,将后部...

yysue
昨天
1
0
数据结构与算法1

第一个代码,描述一个被称为BankAccount的类,该类模拟了银行中的账户操作。程序建立了一个开户金额,显示金额,存款,取款并显示余额。 主要的知识点联系为类的含义,构造函数,公有和私有。...

沉迷于编程的小菜菜
昨天
1
0
从为什么别的队伍总比你的快说起

在机场候检排队的时候,大多数情况下,别的队伍都要比自己所在的队伍快,并常常懊悔当初怎么没去那个队。 其实,最快的队伍只能有一个,而排队之前并不知道那个队快。所以,如果有六个队伍你...

我是菜鸟我骄傲
昨天
1
0
分布式事务常见的解决方案

随着互联网的发展,越来越多的多服务相互之间的调用,这时候就产生了一个问题,在单项目情况下很容易实现的事务控制(通过数据库的acid控制),变得不那么容易。 这时候就产生了多种方案: ...

小海bug
昨天
3
0
python从零学——scrapy初体验

python从零学——scrapy初体验 近日因为一些事情,需要从网上爬取一些东西,故而想通过使用爬虫来顺便学习下强大的python。现将一些学习中遇到的问题记录下来,以便日后查询 1. 开发环境的准...

咾咔叽
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部