所以我只是在学习Forth,我很好奇是否有人能帮助我理解内存管理的一般工作原理。目前,我只有(一些)使用C堆栈对堆范例的经验。
据我所知,可以在字典中分配,或者在堆上分配。字典是否像C中的堆栈一样更快/更好?但与C不同的是,它没有作用域和自动堆栈回收,所以我想知道是否只对全局数据结构使用字典(如果有的话)。
就堆而言,它很像C吗?堆管理是标准(ANS)概念,还是由实现定义的?
发布于 2016-10-15 02:55:41
基本的问题可能没有以Forth新用户需要的方式回答,所以我将尝试一下。
Forth中的内存可能非常依赖于目标,所以我将把描述限制在最简单的模型中,即扁平的内存空间,其中代码和数据愉快地生活在一起。(相对于分段内存模型,或用于代码的闪存和用于数据的RAM或其他更复杂的模型)
字典通常从内存的底部开始,并由Forth系统向上分配。在一个简单的系统中,这两个堆栈将存在于高内存中,并且通常有两个CPU寄存器指向它们。
在最基本的级别上,只需更改字典指针变量的值即可分配内存。
程序员通常不直接访问这个变量,而是使用一些更高级别的字来控制它。
如前所述,Forth单词'HERE‘返回字典空间中的下一个可用地址。这里没有提到的是,这里通过获取变量DP的值来定义。(此处为系统依赖项,但对于描述很有用)
在Forth中,'HERE‘可能看起来像这样:
:这里( -- addr) DP @;
就这样。
为了分配一些内存,我们需要在这里向上移动,我们使用单词'ALLOT‘来实现。
'ALLOT‘的Forth定义只是从参数堆栈中获取一个数字,并将其添加到DP中的值。
:ALLOT (n --) DP +!;\ '+!‘
当我们创建一个新的定义时,ALLOT被第四个系统使用,这样我们创建的内容就可以安全地保存在'ALLOTed‘内存中。
不是很明显的是,分配可以采用负数,因此可以向上或向下移动字典指针。因此,您可以分配一些内存,并像这样返回它:
然后像这样释放它:
十六进制-100分配
所有这些都表明,这是Forth系统中最简单的内存管理形式。在单词‘BUFFER’的定义中可以看到这个用法的一个例子:
:BUFFER:(n --)创建分配;
‘'BUFFER:’在字典中“创建”一个新的名字(create使用allot为名字腾出空间),然后在名字后面分配n字节的内存和你的Forth系统可能使用的任何相关的内务字节
所以现在要分配一个命名内存块,我们只需输入:
标记FOO \标记内存当前结束的位置
现在我们有了一个名为IN_BUFFER的8K字节的缓冲区。如果想要在Standard Forth中回收该空间,我们可以输入' FOO‘,那么在字典中FOO之后分配的所有内容都将从Forth系统中删除。
但是如果你想要临时的内存空间,“HERE”上面的所有东西都可以免费使用!
因此,您可以简单地指向一个地址并使用它,如果您想这样的话
:MYMEMORY here 200 +;\ MYMEMORY指向此处上方未分配的内存
\ MYMEMORY moves with HERE. be aware.MYMEMORY HEX 1000擦除\用2K字节的0填充
Forth通常用于高性能嵌入式应用程序,其中动态内存分配可能导致不可靠的代码,因此首选使用ALLOT的静态分配。然而,较大的系统有一个堆,并使用分配、释放和调整大小,就像我们在C中使用malloc等一样。
高炉
发布于 2012-05-16 05:31:56
彼得·莫特森写得很好。我将添加一些可能对C程序员有所帮助的注释。
堆栈最接近于C术语中的“自动”变量,也就是通常所说的局部变量。您可以在某些forths中为堆栈值命名,但大多数程序员都会尝试编写代码,因此不需要命名这些值。
从C编程的角度来看,字典最好被看作是“静态数据”。您可以在字典中保留地址范围,但通常您将使用ALLOT和相关单词来创建静态数据结构和池,这些结构和池在分配后不会改变大小。如果要实现可实时增长的链表,则可以为所需的链接单元格分配足够的空间,并编写单词以维护可从中绘制的空闲单元格列表。自然会有这类东西的实现,而编写自己的实现是磨练指针管理技能的好方法。
堆分配在许多现代Forth中都可用,标准定义了allocation、FREE和realloc()等字,这些字的工作方式类似于C中的malloc()、free()和realloc()。它们返回的内存来自OS系统堆,通常将地址存储在变量或其他比堆栈更持久的结构中是一个好主意,这样在释放它之前就不会无意中丢失指针。作为附注,如果发生错误,这些字(以及文件i/o字)将在堆栈上返回非零的状态。此约定非常适合异常处理机制,并允许您编写如下代码:
variable PTR
1024 allocate throw PTR !
\ do some stuff with PTR
PTR @ free throw
0 PTR !或者是一个更复杂的分配/释放的例子:
\ A simple 2-cell linked list implementation using allocate and free
: >link ( a -- a ) ;
: >data ( a -- a ) cell + ;
: newcons ( a -- a ) \ make a cons cell that links to the input
2 cells allocate throw tuck >link ! ;
: linkcons ( a -- a ) \ make a cons cell that gets linked by the input
0 newcons dup rot >link ! ;
: makelist ( n -- a ) \ returns the head of a list of the numbers from 0..n
0 newcons dup >r
over 0 ?do
i over >data ! linkcons ( a -- a )
loop >data ! r> ;
: walklist ( a -- )
begin dup >data ? >link @ dup 0= until drop ;
: freelist ( a -- )
begin dup >link @ swap free throw dup 0= until drop ;
: unittest 10 makelist dup walklist freelist ;发布于 2012-03-29 15:48:42
一些Forth实现支持返回堆栈帧上的局部变量和分配内存块。例如在SP-Forth中
lib/ext/locals.f
lib/ext/uppercase.f
100 CONSTANT /buf
: test ( c-addr u -- ) { \ len [ /buf 1 CHARS + ] buf }
buf SWAP /buf UMIN DUP TO len CMOVE
buf len UPPERCASE
0 buf len + C! \ just for illustration
buf len TYPE
;
S" abc" test \ --> "ABC"https://stackoverflow.com/questions/9882326
复制相似问题