建站saas,石龙镇仿做网站,做私房蛋糕在哪些网站写东西,开发软件公司文章目录 关于IRIS/Cach进程内存溢出解决方案 描述原因相关系统变量$ZSTORAGE$STORAGE 什么情况下进程内存会变化#xff1f;内存不足原理解决方案 关于 IRIS/Cach进程内存溢出解决方案 描述
在IRIS/Cach中#xff0c;进程内存溢出错误是指一个进程#xff08;例如运行中的… 文章目录 关于IRIS/Caché进程内存溢出解决方案 描述原因相关系统变量$ZSTORAGE$STORAGE 什么情况下进程内存会变化内存不足原理解决方案 关于 IRIS/Caché进程内存溢出解决方案
描述
在IRIS/Caché中进程内存溢出错误是指一个进程例如运行中的作业JOB、应用程序或服务在执行过程中消耗了超过其分配内存限制的内存资源导致操作系统无法继续为其提供足够的内存空间。这可能会导致进程崩溃、运行缓慢或产生不稳定的行为。
原因
进程内存溢出错误可能由以下情况引起 内存泄漏进程中的代码在使用完内存后未正确释放导致内存逐渐耗尽最终导致溢出。 大量数据处理处理大量数据时如果未及时释放已使用的内存可能会导致内存耗尽。 递归调用递归调用未正确终止或控制可能导致堆栈溢出最终影响进程的内存。
在IRIS/Caché中会提示STORE错误。
相关系统变量
在讲原理之前需要先了解两个系统变量$STORAGE与$ZSTORAGE
$ZSTORAGE $ZSTORAGE包含进程私有内存的最大内存量(以KB为单位)。 USERw $zs
262144可以在Portal中更改最大每进程内存(KB)系统配置设置来更改$ZSTORAGE默认值。默认值为262144KB256M如下截图 $STORAGE $STORAGE返回可用于当前进程中的变量存储的字节数。 $STORAGE的初始值由$ZSTORAGE的值确定该值是该进程可用的最大内存量。 $ZSTORAGE值以千字节为单位越大$STORAGE值以字节为单位越大。但$ZSTORAGE和$STORAGE之间的关系不是绝对的11。 USERw $s
268313368
USERw $s/1024
262024.7734375
USERw $s/1024/1024
255.8835678100585938什么情况下进程内存会变化
使用set命令进程内存$STORAGE会减少。
ClassMethod Store()
{w $s,!s name yxw $s,!s age 18w $s,!
}注可观察到减小的数量为8的倍数。也就是说以字节为单位进行递减。
USERd ##class(M.Store).Store()
268307096
268307088
268307080重复局部变量不会减小进程内存$STORAGE。
ClassMethod Store1()
{w $s,!s name yxw $s,!s age 18w $s,!s name yxw $s,!s age 18w $s,!w name,!w $s,!w age,!w $s,!
}USERd ##class(M.Store).Store1()
268306968
268306960
268306952
268306952
268306952
yx
268306952
18
268306952局部变量名称大小对进程内存$STORAGE没有影响并不是说变量名称越长所占内存越多。
ClassMethod Store2()
{w $s,!s name yxw $s,!s namenamenamenamenamename yxw $s,!s namenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamenamename yxw $s,!
}USERd ##class(M.Store).Store2()
268306968
268306960
268306952
268306944局部变量所保存的值影响进程内存$STORAGE。
ClassMethod Store3()
{w $s,!s name yxw $s,!s name yxyxyxyxw $s,!s name yxyxyxyxyxyxyxyxw $s,!s name yxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxw $s,!
}注可观察到字符串越长所占用的内存越多。
USERd ##class(M.Store).Store3()
268306968
268306960
268306936
268306904
268306840多维数组会影响进程内存$STORAGE下标越多占用的内存越多。
ClassMethod Store4()
{w $s,!s array(1) 1w $s,!s array(2) 2w $s,!s array(3) yxyxw $s,!s array(4) yxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxw $s,!
}USERd ##class(M.Store).Store4()
268306968
268306896
268306888
268306680
268306552删除局部变量多维数组可以使进程内存$STORAGE增加或恢复。
ClassMethod Store5()
{w $s,!s name yxw $s,!s name yxyxyxyxw $s,!k namew 删除局部变量后 _ $s,!w $s,!s array(1) 1w $s,!s array(2) 2w $s,!s array(3) yxyxw $s,!s array(4) yxyxyxyxyxyxyxyxyxyxyxyxyxyxyxyxw $s,!k arrayw 删除多维数组后 _ $s,!
}USERd ##class(M.Store).Store5()
268306968
268306960
268306936
删除局部变量后268306968
268306968
268306896
268306888
268306680
268306552
删除多维数组后268306968使用NEW命令时$STORAGE会减少。因为N会增加堆栈级别也就意味发生堆栈级别改变的命令都会使内存减少。
ClassMethod Store6()
{w $s,!nw $s,!nw $s,!nw $s,!
}注第一次使用New命令时减少13336后续的New命令均减少12228。
USERd ##class(M.Store).Store6()
268306968
268293632
268281344
268269056块语法IF、ELES、FOR、TRY、CATCH命令不会使用$STORAGE会减少。
ClassMethod Store7()
{w $s,!if 1 {w $s,!if 1 {w $s,!} } else {w $s,!}w $s,!try {w $s,!} catch {w $s,!}w $s,!for {w $s,!b}
}
USERd ##class(M.Store).Store7()
268288144
268288144
268288144
268288144
268288144
268288144
268288144b^
BREAKzStore719^M.Store.1
USER 3f2$STORAGE值不受设置的进程私有Global、与临时Global影响。
ClassMethod Store8()
{w $s,!k ^yxw $s,!k ^||yxw $s,!s ^yx(name) yxw $s,!s ^yx(age) 18w $s,!s ^||yx(address) chinaw $s,!s ^||yx(work) 码农w $s,!
}USERd ##class(M.Store).Store8()
268287376
268287376
268287376
268287376
268287376
268287376
268287376局部变量字符串长度与进程内存关系 每增加4个字符会增加8Byte内存空间大小无论中文英文字符。
ClassMethod Store9()
{w 英文所占内存大小,!s str w 0 _ _ str _ _$s ,!for i 1 : 1 : 40 {s str str _ xw i _ _ str _ _$s ,!}w 中文所占内存大小,!w $s,!s name 姚w $s,!s name 姚鑫w $s,!s name 姚鑫姚w $s,!s name 姚鑫姚鑫w $s,!s name 姚鑫姚鑫姚w $s,!s name 姚鑫姚鑫姚鑫w $s,!s name 姚鑫姚鑫姚鑫姚w $s,!s name 姚鑫姚鑫姚鑫姚鑫w $s,!s name 姚鑫姚鑫姚鑫姚鑫姚鑫姚鑫w $s,!s name 姚鑫姚鑫姚鑫姚鑫姚鑫姚鑫姚鑫姚鑫w $s,!
}USER d ##class(M.Store).Store9()
英文所占内存大小
0 268311440
1 x268311432
2 xx268311432
3 xxx268311432
4 xxxx268311424
5 xxxxx268311424
6 xxxxxx268311424
7 xxxxxxx268311424
8 xxxxxxxx268311408
9 xxxxxxxxx268311408
10 xxxxxxxxxx268311408
11 xxxxxxxxxxx268311408
12 xxxxxxxxxxxx268311408
13 xxxxxxxxxxxxx268311408
14 xxxxxxxxxxxxxx268311408
15 xxxxxxxxxxxxxxx268311408
16 xxxxxxxxxxxxxxxx268311376
17 xxxxxxxxxxxxxxxxx268311376
18 xxxxxxxxxxxxxxxxxx268311376
19 xxxxxxxxxxxxxxxxxxx268311376
20 xxxxxxxxxxxxxxxxxxxx268311376
21 xxxxxxxxxxxxxxxxxxxxx268311376
22 xxxxxxxxxxxxxxxxxxxxxx268311376
23 xxxxxxxxxxxxxxxxxxxxxxx268311376
24 xxxxxxxxxxxxxxxxxxxxxxxx268311376
25 xxxxxxxxxxxxxxxxxxxxxxxxx268311376
26 xxxxxxxxxxxxxxxxxxxxxxxxxx268311376
27 xxxxxxxxxxxxxxxxxxxxxxxxxxx268311376
28 xxxxxxxxxxxxxxxxxxxxxxxxxxxx268311376
29 xxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311376
30 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311376
31 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311376
32 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
33 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
34 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
35 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
36 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
37 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
38 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
39 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
40 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx268311312
中文所占内存大小
268311312
268311304
268311304
268311304
268311296
268311296
268311296
268311296
268311280
268311280
268311248内存不足原理
如上一节所述我们知道了什么情况下内存会发生变化。这里我们模拟常见内存溢出的一种情况
在处理大量数据时使用多维数组用于分类或汇总数据如果多维数据下标节点越来越多那么使用的内存会越来越多。如果未及时释放已使用的内存会导致内存耗尽。示例如下
ClassMethod Store11()
{for {s yx($i(yx)) $i(yx)}q $$$OK
}USER d ##class(M.Store).Store11()s yx($i(yx)) $i(yx)^
STOREzStore112^M.Store.1
USER 3f2原理$STORAGE值可以是正数也可以是负数。值为零并不表示没有可用存储但表示存储极度短缺。如果$STORAGE减少到小于或接近与零则会在某个时刻发生store错误。例如如果$STORAGE减少到40则为另一个局部变量分配存储可能会由于store错误而失败这表明没有足够的可用存储空间来存储局部变量值或建立新的堆栈级别。
ClassMethod Store11()
{for {s yx($i(yx)) $i(yx)if ($s 1000){w $s,!}}q $$$OK
}
USER d ##class(M.Store).Store11()
216
176
120
64
40s yx($i(yx)) $i(yx)^
STOREzStore112^M.Store.1实际上STORE内存错误可以通过设置陷阱来捕获异常。但是进入陷阱时并不会主动释放内存。示例如下
ClassMethod Store12()
{s $zt Errorfor {s yx($i(yx)) $i(yx)}q $$$OK
Errors $zt w 内存溢出时内存大小 _ $s,!q $ze
}USER d ##class(M.Store).Store12()
内存溢出时内存大小440当store错误发生并用陷阱进行拦截时系统会自动为进程提供1MB的额外内存用与错误处理。系统不会更改$ZSTORAGE的大小允许$STORAGE进一步进入负数值。示例如下 当第一个store错误发生时系统在内部将进程指定为内存不足状态。而在此低内存状态下该进程可以继续分配内存并且$STORAGE的值可以继续减少到更低的负数。在此低内存状态下进程可能会释放一些已分配的内存从而导致$STORAGE的值上升。因此$STORAGE的值可以在一个值范围内上升或下降而不会发出额外的store错误。
注第一个store错误提供了一些内存缓冲允许进程调用诊断、执行磁盘保存、正常退出、释放内存并继续。
注当发生第一个store错误进程会消耗额外的内存。当$STORAGE的值达到-1048576时会出现第二个STORE错误。如果进程发生第二个STORE错误则没有更多的内存可供该进程使用并且进一步的进程操作将变得不可预测。这个进程会立即终止。
注如果在陷阱当中发生内存再次溢出进程是直接关闭的。即使设置了$zt 也不管用这种情况如果陷阱中有记录日志或有解锁操作等将不会就即使会发生锁无法即使释放。
如下示例锁永远也不会得到释放。
ClassMethod Store14()
{s $zt Errorw 加锁,!l ^yx(node):3for {s yx($i(yx)) $i(yx)}q $$$OK
Errors $zt w 内存溢出时内存大小 _ $s,!for {s yx($i(yx)) $i(yx)w $s,!}w 陷阱内存溢出解锁失败,!l -^yx(node):3q $ze
}解决方案
要解决内存不足的问题首先要做到以下几点 在使用多维数组时要设置陷阱进行异常拦截。 在发生内存溢出时在陷阱中将多维数据kill删除掉恢复内存。 如果发生了二次内存溢出。需要讲多维数组方法声明为单独的方法。用于外层接口调用进行陷阱二次拦截。
示例如下
注$SYSTEM.Process.MemoryAutoExpandStatus()方法可以提示出内存溢出的原因。
模拟二次内存溢出代码如下
ClassMethod Store14()
{s $zt Errorw 加锁,!l ^yx(node):3for {s yx($i(yx)) $i(yx)}q $$$OK
Errors $zt w 第一次内存溢出错误 _ $ze,!w 陷阱错误代码 _ $SYSTEM.Process.MemoryAutoExpandStatus(),!if ($SYSTEM.Process.MemoryAutoExpandStatus() 1) {w 1——抛出STORE错误因为进程超过了$ZSTORAGE值并且没有自动扩展$ZSTORAGE值。,!}b ; 陷阱for {s yx($i(yx)) $i(yx)w $s,!}w 陷阱内存溢出解锁失败,!l -^yx(node):3q $ze
}基于上述第三点需要单独的方法去调用用于外层接口调用进行陷阱二次拦截。示例如下
ClassMethod Store15()
{s $zt Errorw 开始时内存_ $s,!d ..Store14()w 结束时内存_ $s,!q $$$OK
Errors $zt w 陷阱中剩余_ $s,!w 陷阱错误代码 _ $SYSTEM.Process.MemoryAutoExpandStatus(),!if ($SYSTEM.Process.MemoryAutoExpandStatus() 2) {w 2——抛出STORE错误因为进程超过了$ZSTORAGE值并且$ZSTORAGE值被自动扩展了1M。,!}w 第二次内存溢出错误 _ $ze,!l -^yx(node):3w 解锁,!q $ze
}根据上图可观察到在外层陷阱进行拦截到第二次内存溢出错误时可发现系统为我们自动清理了内存并将内存恢复到$ZSTORAGE最大值268302712。并且也成功解锁。
注上面示例是为了解决内存二次溢出的情况通过这种方式防止进程直接结束实际上应该在第一次内存溢出时就应该将多维数组进行kill恢复内存。
注实际上不应该在陷阱当中写入过多的业务逻辑导致二次内存溢出。
以上是个人对IRIS/Caché进程内存溢出的一些理解由于个人能力有限欢迎大家提出意见共同交流。