第十五章 Caché 变量大全 $STORAGE 变量
包含可用于局部变量存储的字节数。
大纲
$STORAGE
$S
描述
$STORAGE
返回可用于当前进程分区中的本地变量存储的字节数。 $STORAGE
的初始值由$ZSTORAGE
的值确定,该值是该进程可用的最大内存量。 $ZSTORAGE
值(以千字节为单位)越大,$STORAGE
值(以字节为单位)越大。但是,$ZSTORAGE
和$STORAGE
之间的关系不是简单的1:1比率。
$STORAGE
值受以下操作影响:
- 在局部变量空间中定义局部变量(例如,使用
set
命令)时,$STORAGE
会减少。$STORAGE
的减少对应于存储局部变量的值所需的空间量;局部变量名称的大小对$STORAGE
没有影响,但下标级别的数量确实会影响$STORAGE
。$STORAGE
值随着删除局部变量(例如,通过使用kill
命令)而增加。 - 发出
NEW
命令时,$STORAGE
会减少。NEW
建立一个新的执行级别;在上一个执行级别为局部变量(无论是否使用)预留的空间在新的执行级别上不可用。最初的new
项目减少了大约15000的$STORAGE
;后续的每个new
项目减少了12288的$STORAGE
。发出QUIT
命令退出执行级别时,$STORAGE
值会增加。 - 当定义控制流语句(如
IF
或FOR
)或块结构(如TRY
和CATCH
)时,$STORAGE
会减少。分配存储是用来编译这些结构的,而不是用来执行它们的。因此,无论是否循环或循环多少次,For
语句都会消耗相同的存储量;无论执行多少分支,每个If
、ELSEIF
和ELSE
子句都会消耗一定数量的存储。空间是从编译代码的进程分配的。请注意,for
循环通常将局部变量定义为计数器。
$STORAGE
值不受设置进程私有全局变量、全局变量或特殊变量的影响。$STORAGE
值不受更改名称空间的影响。启用长字符串不会影响$STORAGE
值,因为在进程分区中没有分配长字符串存储。
不能使用SET
命令修改$STORAGE
特殊变量。尝试这样做会导致<SYNTAX>
错误。
内存不足和<store>
错误
$STORAGE
值可以是正数,也可以是负数。值为零并不表示没有可用存储,但表示存储极度短缺。如果$STORAGE
减少到小于零,则会在某个时刻发生<store>
错误。例如,如果$STORAGE
减少到-7000,则为另一个局部变量分配存储可能会由于<store>
错误而失败,这表明没有足够的可用存储空间来存储局部变量值或建立新的执行级别。
第一个<store>
错误发生在$STORAGE
的某个值小于零时;确切的负$STORAGE
值阈值取决于上下文。此<store>
错误指示必须通过增加$ZSTORAGE
或通过KILL
或QUIT
操作释放一些已分配的存储来获得额外的存储。当第一个<store>
错误发生时,Caché会自动为进程提供1MB的额外内存,以启用错误处理和恢复。Caché不会更改$ZSTORAGE
;它允许$STORAGE
进一步进入负数值。
当第一个<store>
错误发生时,Caché在内部将进程指定为内存不足状态。而在此低内存状态下,该进程可以继续分配内存,并且$STORAGE
的值可以继续减少到更低的负数。在此低内存状态下,进程可能会释放一些已分配的内存,从而导致$STORAGE
的值上升。因此,$STORAGE
的值可以在一个值范围内上升或下降,而不会发出额外的<store>
错误。此外,在第一个<store>
错误之后,可能会看到由于Caché释放了一些内部内存而导致$STORAGE
的小幅上升。
第一个<store>
错误提供了一些内存缓冲,允许进程调用诊断、执行磁盘保存、正常退出、释放内存并继续。
进程保持低内存状态,直到发生以下任何一种情况:
- 该过程提供了足够的内存。进程可以通过增加
$ZSTORAGE
分配和/或通过KILL
或QUIT
操作释放分配的存储来实现这一点。当$STORAGE
的值超过256K(或$ZSTORAGE
的25%,以较小者为准)时,Caché将进程从低内存状态移除。此时,如果可用内存减少到负数,该进程可能会再次发出<store>
错误。 - 该进程会消耗额外的内存。当
$STORAGE
的值达到-1048576时,会出现第二个<STORE>
错误。如果进程到达这一点,则没有更多的内存可供该进程使用,并且进一步的进程操作将变得不可预测。这一过程很可能会立即终止。
可以通过调用$SYSTEM.Process.MemoryAutoExpanStatus()
方法来确定<store>
错误的原因。
示例
以下示例显示当$ZSTORAGE
设置为较小的值时,$STORAGE
如何变小。请注意,这两个值之间的关系(比率)是可变的:
/// d ##class(PHA.TEST.SpecialVariables).STORAGE()
ClassMethod STORAGE()
{
SET $ZS=262144
FOR i=1:1:10 {
WRITE "$ZS=",$ZS," $S=",$S," ratio=",$NORMALIZE($S/$ZS,3),!
IF $ZS>30000 {SET $ZS=$ZS-30000 }
}
}
以下示例显示了在分配局部变量时$STORAGE
如何减少,而在终止局部变量时$STORAGE
如何增加:
/// d ##class(PHA.TEST.SpecialVariables).STORAGE1()
ClassMethod STORAGE1()
{
WRITE "$STORAGE=",$S," initial value",!
FOR i=1:1:30 {
SET a(i)="abcdefghijklmnopqrstuvwxyz"
WRITE "$STORAGE=",$S,!
}
KILL a
WRITE !,"$STORAGE=",$S," after KILL",!
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).STORAGE1()
$STORAGE=22551864 initial value
$STORAGE=22551728
$STORAGE=22551664
$STORAGE=22551408
$STORAGE=22551344
$STORAGE=22551280
$STORAGE=22551216
$STORAGE=22551152
$STORAGE=22551088
$STORAGE=22551024
$STORAGE=22550960
$STORAGE=22550896
$STORAGE=22550832
$STORAGE=22550768
$STORAGE=22550704
$STORAGE=22550640
$STORAGE=22550320
$STORAGE=22550256
$STORAGE=22550192
$STORAGE=22550128
$STORAGE=22550064
$STORAGE=22550000
$STORAGE=22549936
$STORAGE=22549872
$STORAGE=22549808
$STORAGE=22549744
$STORAGE=22549680
$STORAGE=22549616
$STORAGE=22549552
$STORAGE=22549488
$STORAGE=22549424
$STORAGE=22551856 after KILL
以下示例显示分配的局部变量的下标级别数如何影响$STORAGE
:
/// d ##class(PHA.TEST.SpecialVariables).STORAGE2()
ClassMethod STORAGE2()
{
WRITE "无下标:",!
SET before=$S
SET a="abcdefghijklmnopqrstuvwxyz"
WRITE " 分配的内存 ",before-$S,!
KILL a
WRITE "1个下标级别:",!
SET before=$S
SET a(1)="abcdefghijklmnopqrstuvwxyz"
WRITE " 分配的内存 ",before-$S,!
KILL a(1)
WRITE "9个下标级别:",!
SET before=$S
SET a(1,2,3,4,5,6,7,8,9)="abcdefghijklmnopqrstuvwxyz"
WRITE " 分配的内存 ",before-$S,!
KILL a(1,2,3,4,5,6,7,8,9)
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).STORAGE2()
无下标:
分配的内存 80
1个下标级别:
分配的内存 128
9个下标级别:
分配的内存 640
以下示例显示了当NEW
建立新的执行级别时,$STORAGE
如何减少(在该级别变得不可用):
/// d ##class(PHA.TEST.SpecialVariables).STORAGE3()
ClassMethod STORAGE3()
{
WRITE "不断增加的级别:",!
FOR i=1:1:10 {
WRITE "$STORAGE=",$S,! NEW
}
}
DHC-APP>d ##class(PHA.TEST.SpecialVariables).STORAGE3()
不断增加的级别:
$STORAGE=22550456
$STORAGE=22536704
$STORAGE=22524416
$STORAGE=22512128
$STORAGE=22499840
$STORAGE=22487552
$STORAGE=22475264
$STORAGE=22462976
$STORAGE=22450688
$STORAGE=22438400
下面的示例显示了$STORAGE
如何随着局部变量的赋值而减少,直到它进入内存不足状态,并发出<store>
错误。<store>
错误由Catch
块捕获,该块调用StoreErrorReason()
方法来确定导致错误的原因。请注意,进入CATCH
块会消耗大量存储空间。一旦进入CATCH
块,此示例将再分配一个变量。
/// d ##class(PHA.TEST.SpecialVariables).STORAGE4()
ClassMethod STORAGE4()
{
TRY {
WRITE !,"TRY 块",!
SET init=$ZSTORAGE
SET $ZSTORAGE=456
WRITE "初始化 $STORAGE=",$STORAGE,!
FOR i=1:1:10000 {
SET pre=$STORAGE
SET var(i)="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
IF $STORAGE<0 {
WRITE "var(",i,") 负内存=",$STORAGE,!
} ELSEIF pre<$STORAGE {
WRITE "var(",i,") 新分配 $S=",$STORAGE,!
} ELSE {
WRITE "var(",i,") $S=",$STORAGE,!
}
}
}
CATCH myexp {
WRITE !,"CATCH 块异常处理",!!
WRITE "Name: ",$ZCVT(myexp.Name,"O","HTML"),!
IF myexp.Name="<STORE>" {
WRITE "内存错误原因=",
$SYSTEM.Process.StoreErrorReason(),!
}
WRITE "$S=",$STORAGE,!
SET j=i
SET var(j)="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
WRITE "var(",j,") 增加了一个变量 $S=",$STORAGE,!
SET $ZSTORAGE=init
RETURN
}
}
...
var(2039) $S=48152
var(2040) $S=48024
var(2041) $S=47896
var(2042) $S=47768
var(2043) $S=47640
var(2044) $S=47512
var(2045) $S=47384
var(2046) $S=47256
var(2047) $S=47128
CATCH 块异常处理
Name: <STORE>
内存错误原因=1
$S=39240
var(2048) 增加了一个变量 $S=6336