从代码中调用函数“DoStackOverflow”一次,您将得到Delphi引发的EStackOverflow错误,并显示消息“stack overflow”。
function DoStackOverflow : integer; begin result := 1 + DoStackOverflow; end;这个“堆栈”是什么?为什么使用上面的代码会出现溢出?
因此,DoStackOverflow函数递归地调用自己——没有“退出策略”——它只是继续旋转,从不退出。
您可以做的一个快速修复方法是清除明显的bug,并确保函数在某个点存在(这样您的代码就可以从调用函数的位置继续执行)。
你继续前进,你永远不会回头,不关心现在已经解决的bug/异常。
然而,问题仍然存在:这个堆栈是什么?为什么会出现溢出?
当您开始在Delphi中编程时,您可能会遇到类似上面的错误,您可以解决它并继续前进。这与内存分配有关。大多数情况下,只要释放所创建的内容,您就不会关心内存分配。
随着您在Delphi中获得更多的经验,您开始创建自己的类,实例化它们,关心内存管理等等。
您将在帮助中阅读类似“局部变量(在过程和函数中声明)驻留在应用程序堆栈中”的内容,并且类也是引用类型,因此它们不会在赋值时复制,而是通过引用传递,并在堆上分配。
那么,什么是“堆栈”,什么是“堆”?
在Windows上运行应用程序时,内存中有三个区域用于存储数据:全局内存、堆和堆栈。
全局变量(其值/数据)存储在全局内存中。全局变量的内存在程序启动时由应用程序保留,并在程序终止前保持分配状态。全局变量的内存称为“数据段”。
由于全局内存只在程序终止时分配和释放一次,因此本文不关心它。
堆栈和堆是进行动态内存分配的地方:为函数创建变量时,向函数发送参数并使用/传递其结果值时,创建类实例时。
在函数中声明变量时,保存变量所需的内存将从堆栈中分配。您只需编写“var x:integer”,在函数中使用“x”,当函数退出时,您不关心内存分配或释放。当变量超出范围(代码退出函数)时,堆栈上占用的内存将被释放。
堆栈内存是使用后进先出方法动态分配的。
在Delphi程序中,堆栈内存由
您不必显式释放堆栈上的内存,因为当您(例如)向函数声明局部变量时,内存会自动神奇地分配给您。当函数退出时(有时甚至由于Delphi编译器优化而提前退出),变量的内存将自动神奇地释放。
默认情况下,堆栈内存大小对于您的Delphi程序(尽管很复杂)来说是足够大的。项目链接器选项上的“最大堆栈大小”和“最小堆栈大小”值指定默认值——在99.99%范围内,您无需更改此值。
将堆栈视为一堆内存块。当您声明/使用局部变量时,Delphi内存管理器将从顶部拾取块并使用它,当不再需要时,它将返回堆栈。
使用堆栈中的局部变量内存时,局部变量在声明时不会初始化。在某个函数中声明一个变量“var x:integer”,并在输入该函数时尝试读取该值——x将有一些“奇怪的”非零值。所以,在读取局部变量的值之前,请始终初始化(或设置值)。
由于后进先出(LIFO),堆栈(内存分配)操作速度很快,因为管理堆栈只需要几个操作(推送、弹出)。
堆是存储动态分配内存的内存区域。创建类的实例时,将从堆中分配内存。
在Delphi程序中,堆内存由/when使用
堆内存没有很好的布局,分配内存块是有一定顺序的。堆看起来像一罐弹珠。堆中的内存分配是随机的,这里的一个块比那里的一个块大。因此,堆操作比堆栈上的操作慢一点。
当您请求一个新的内存块(即创建一个类的实例)时,Delphi内存管理器将为您处理这个问题:您将得到一个新的内存块或一个已使用并丢弃的内存块。
堆由所有虚拟内存(RAM和磁盘空间)组成。
现在,关于内存的所有内容都已清楚,您可以安全地(在大多数情况下)忽略上述内容,继续编写Delphi程序,就像昨天一样。
当然,您应该知道何时以及如何手动分配/释放内存。
之所以提出“EStackOverflow”(从本文开始),是因为每次调用DoStackOverflow时,都会从堆栈中使用一段新的内存,并且堆栈具有限制。就这么简单。
C++中new和Delphi运算符的主要区别在于new被用来为对象或数组分配内存,而DELATE用于释放使用新运算符分配的内存。 有两种类型的记忆作为静态和动态记忆。假设一个语句,比如int a;int数组[10];程序员已经知道这些变量需要多...
...止其他人操纵这些加载项文件。 本文将向您展示如何在Delphi可执行文件中嵌入(和使用)声音文件、视频剪辑、动画以及更一般的任何类型的二进制文件。对于最通用的用途,您将看到如何将MP3文件放入Delphi exe中。 资源文...
在Delphi应用程序中使用菜单或弹出菜单时,在大多数情况下,都是在设计时创建菜单项的。每个菜单项都由一个TMenuItem Delphi类表示。当用户选择(单击)一个项目时,OnClick事件将被触发,以供您(作为开发人员)获取该事件并...
简而言之,Delphi项目只是组成由Delphi创建的应用程序的文件集合。DPR是用于Delphi项目文件格式的文件扩展名,用于存储与项目相关的所有文件。这包括其他Delphi文件类型,如表单文件(DFM)和单元源文件(.PASs)。 由于Delphi...
自Delphi 2006以来的所有Delphi版本都有一个更新的内存管理器,该管理器速度更快,功能更丰富。 “新”内存管理器最出色的功能之一是允许应用程序注册(和注销)预期内存泄漏,并在程序关闭时报告意外内存泄漏。 使用De...
...形式,允许您选择、插入、更新、查找数据位置等。 delphi中的tquery 如果要在应用程序中使用SQL,您将非常熟悉TQuery组件。Delphi使您的应用程序能够通过TQuery组件直接使用SQL语法来访问Paradox和dBase表(使用本地SQL—ANSI标准SQL...
Delphi的编程语言是强类型语言的一个例子。这意味着所有变量必须是某种类型。类型本质上是一种数据的名称。当我们声明一个变量时,我们必须指定它的类型,它决定了变量可以保存的值集以及可以对其执行的操作。 Delphi...
...的结构。还演示了创建虚拟和嵌套数据集字段的方法。 理解ClientDataSet索引ClientDataSet不会从加载的数据中获取其索引。如果需要,必须显式定义索引。本文将向您展示如何在设计时或运行时执行此操作。 导航和编辑ClientDataSet...
...活动,最终降低计算机的速度。 02 2006年 何时在delphi应用程序中创建表单 假设您要设计一个包含主窗体和两个附加(模态)窗体的程序。通常,根据您的Delphi版本,Delphi将把表单插入到项目单元(DPR文件)中,并包...
...或图形的容器。本文将向您展示如何使用TClipboard对象在Delphi应用程序中实现剪切复制粘贴功能。 一般剪贴板 您可能知道,剪贴板一次只能保存一段相同类型的数据进行剪切、复制和粘贴。如果我们以相同的格式将新信息发...