gpt4 book ai didi

memory-management - 如何跟踪 Forth 中分配的所有字符串并按时释放它们?

转载 作者:行者123 更新时间:2023-12-02 18:08:37 25 4
gpt4 key购买 nike

我看到很多 Forth 代码只是在做 s"Hello "s"world"s+ 好像没什么,但现在我想了一下,这实际上分配了 3 个指针,并丢失了两个指针他们走向伟大的虚无。 slurp-file 的大多数使用都存在同样的问题。

但是,如果我需要将分配的每个字符串地址放入临时位置以便稍后释放它们,例如 s"foo"over >r ( ... do some ... ) r> free,我要失去理智了。这方面的最佳实践是什么?

我没有看到很多 Forth 代码考虑内存分配,而且它的堆栈方面似乎处于一种“即发即忘”的情绪。

实用

我正在开发一个提供 HTML 文件的 Web 服务器,虽然请求保存在可重用的 pad 中,但另一方面,响应是混合文件和字符串连接。

这意味着,如果我让服务器在互联网上运行一段时间,并让你在那里找到的各种机器人玩它,我可能会丢失大量的内存,只是为了回答它们离开。

问题

因此,我向这里活跃的 Forth 社区寻求最佳实践。

我应该:

  1. 在程序中的每次内存分配后运行,并检查是否有时释放它们
  2. 让程序运行并在达到限制后重新启动
  3. 使用 gforth 垃圾收集器扩展
  4. 准备大量内存专用于请求,并在响应结束时立即释放所有内容

(1) 是我最可怕的噩梦中的一个场景
(2)是一种偷懒的方式,但也不是那么糟糕
(3) 我查看了代码,这对我来说似乎太过分了
(4) 是我真正想要的目标,但有点雄心勃勃

奖励:如果我必须实现解决方案 (4),我会做什么

  • 我会分配一大块内存并将指针保存在变量中。
  • 然后使用与 here 相同的词来指向其中的下一个空闲位置。
  • 然后为 s+ 和其他字符串操作字编写新版本,将其添加到此处,并按其大小递增
  • 在服务器应答结束时,我将释放初始指针。

这是一个好的策略吗?我错过了什么吗?

最佳答案

简短的回答:你保留一个列表。

s" 并不总是分配新内存

我对 s" 工作原理的解释是错误的。在解释时(在读取文件期间或在交互式终端中),它有效地分配内存,因此你在堆栈上得到一个字符串。但是当 s" 被编译成一个单词时,它的执行会调用 allot ,这会使用现有的字典空间。

Gforth 0.7.3
see s"
34 parse save-mem ; \ interpret
34 parse POSTPONE SLiteral ; \ compile

see save-mem
swap >r dup allocate throw swap 2dup r> -rot move ;

see SLiteral
tuck 2>r POSTPONE AHEAD here 2r> mem, align >r POSTPONE THEN r> POSTPONE Literal POSTPONE Literal ;

see mem,
here over allot swap move ;

POSTPONE AHEAD 允许在读取字符串期间只调用一次进行分配的代码,然后在执行过程中跳过这一部分,直接进入将地址和长度压入字符串的部分堆栈。

这意味着代码中内联的字符串会就地编译,不需要释放。

s" This string should be freed"  \ on the heap

: hello ( -- addr u )
s" This one should not." ; \ in dictionary space

s" 是实现定义的

有些fors为所有s"调用重用相同的缓冲区,而其他一些fors则允许您同时访问2或3个字符串,但下一个将删除现有数据。

因此,您不应将 s" 字符串视为理所当然,如果您想保留它,则应复制它。

如何跟踪分配的所有字符串

因此,主要问题不是 s" 的使用,而主要是 s+slurp-file,它们都调用 内部分配

我使用所谓的“空闲列表”解决了这个问题。每次我使用 s+ 或 slurp-file 时,我都会保留对给定指针的引用,并将其存储在链接列表中以便稍后释放。

代码

\ a simple linked-list keeping track of allocated strings

variable STRBUF-POINTER \ the current head of the list
0 STRBUF-POINTER !

struct
cell% field strbuf-prev \ previous entry
cell% field strbuf-addr \ the string allocated
end-struct strbuf%

: add-strbuf ( addr -- )
strbuf% %alloc >r
( addr ) r@ strbuf-addr !
STRBUF-POINTER @ r@ strbuf-prev !
r> STRBUF-POINTER ! ; \ become the new head

: (?free) ( addr -- )
dup if free throw else drop then ;

: free-strbuf ( -- ) \ walk up the list and free strings
begin
STRBUF-POINTER @
while
STRBUF-POINTER @ >r
r@ strbuf-addr @ (?free) \ free the string
r@ strbuf-prev @ STRBUF-POINTER ! \ prev becomes new head
r> (?free) \ free the struct itself
repeat ;

用法

: my-s+  ( $1 $2 -- $3 )
s+ over add-strbuf ;

: my-slurp-file ( $path -- $content )
slurp-file over add-strbuf ;

: main-process
begin
listen \ wait for client request
( ... use my-s+ and my-slurp-file ... )
send-response
free-strbuf \ we free everything we used
again
;

在我的例子中,这个解决方案似乎足以大幅减少内存使用量。但在某些情况下,您可能希望通过实现regions来改进它:不要在链接列表中为每个字符串创建一个新元素,而是让它们跟踪大的可重用缓冲区,就像我在解决方案(4)中所说的那样。

关于memory-management - 如何跟踪 Forth 中分配的所有字符串并按时释放它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72819086/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com