找回密码
 点一下
查看: 3139|回复: 11

关于war3排泄的机制扫盲

[复制链接]
发表于 2009-8-3 08:54:31 | 显示全部楼层 |阅读模式
恩。。貌似好多人还不知道泄漏是怎么产生的。。

那么在此扫盲一下。
-----------------------------------------------------------------------
知道吗?war3并没有真正的垃圾回收机制。
-----------------------------------------------------------------------
内存的申请流程是这样的:

检索已经使用的空间,是否有“引用计数==0”的空间,有则将此空间用作存储当前信息。

如果没有引用计数==0的空间,那么自动生成一个新的空间,并加入“已经使用”列表中。

举个例子:

set sheep = 1000(1000 引用+1)
set sheep = 1000(1000 引用+1)
set sheep = 1000(1000 引用+1)
set sheep = 1000(1000 引用+1)
set sheep = 1000(1000 引用+1)

set a = 1001(1001 引用+1)

set b = 1002(1002 引用+1)

sheep->1000
a->1001
b->1002

ID:1000[引用:5][羊]
ID:1001[引用:1][死亡骑士]
ID:1002[引用:1][小歪]
.....
这个时候比如:
set a = null的话,1001的引用计数会下降,就变成可以重新利用的地址,变化如下

sheep->1000
a->null(1001引用-1)
b->1002

ID:1000[引用:5][羊]
ID:1001[引用:0][死亡骑士]
ID:1002[引用:1][小歪]
.....
-----------------------------------------------------------------------
那么,泄漏就在这里了。

任何一个变量被赋值(set xx = xx)的时候,都会使变量原来指向对象的空间引用计数-1,新的对象空间引用计数+1
(比如已知a==hero1,set a=unit1的操作会导致hero1的引用计数-1,unit1的计数+1)

但是局部的变量,比如
function xxx ....
local a = xxx
endfunction

这样的函数,本来是应该在结尾的地方有系统默认的set a=null这样的操作的(用来让a指向的空间引用计数-1),但是blz没做出来。

如果一个局部的变量没有在最后set=null,那么他指向的地址空间引用计数将永久+1(永远不会=0),那么在开始说到的那个机制里面,这个空间被认为是永久不可使用的。

于是就泻了。
 楼主| 发表于 2009-8-3 09:01:09 | 显示全部楼层
然后估计会有另外一个线程来回跑,检索所有引用计数==0的空间然后释放掉
回复

使用道具 举报

 楼主| 发表于 2009-8-3 09:03:25 | 显示全部楼层
至于为什么缓存有时候会挂掉,就是因为没有保存引用计数(整数不会引起引用计数的变化),结果war3本身把实际的空间释放掉了或者用来干别的事情了,一读取,数据结构都不一样了,于是就挂了。
回复

使用道具 举报

发表于 2009-8-3 09:13:44 | 显示全部楼层
额,赋值不先减少当前句柄的引用数的么?只是增加新句柄的引用数么………………
回复

使用道具 举报

发表于 2009-8-3 12:13:17 | 显示全部楼层
举出的例子是整数吧?c里面int是值传递不是引用吧,应该we也是这样?

应该举对象的例子的……
回复

使用道具 举报

发表于 2009-8-3 20:24:08 | 显示全部楼层
更了解了,谢
回复

使用道具 举报

发表于 2009-8-4 21:15:37 | 显示全部楼层
LS的说明有一定计算机原理学习的才看得懂...  应该简练一点
回复

使用道具 举报

发表于 2009-8-15 12:46:05 | 显示全部楼层
既然扫盲,这个标题对新人容易产生误导[太难听了]


Memory Leak叫内存泄漏或记忆体漏失,结果就是本该释放的内存被一直闲置,如果游戏过程中时常会有内存泄漏,则会造成游戏速度不断变慢[因为可用内存慢慢变少了]
解决这个问题的措施称之为内存释放,也就是通过一些语句来重新有效的利用被闲置的内存。

set null这个手段是用来解决区域物件变量造成的内存泄漏,也就是例如:
  1. function temp1 takes nothing returns nothing
  2.    local trigger tg=CreateTrigger()
  3.    local unit u
  4.    local timer tm
  5.       call DestroyTrigger(t)
  6.    set tg=null
  7.    set unit=null
  8.    set tm=null  
  9. endfunction
复制代码


而全局变量和非物件变量不set null也不会有内存泄漏发生,例如:
  1. function temp2 takes nothing returns nothing  
  2.     local string s = "不要清我!"
  3.     local integer i = 55
  4.     local real r = 55.55
  5.     local boolean b = true
  6.         set udg_t = CreateTrigger()
  7.     call DestroyTrigger(udg_t)
  8. endfunction
复制代码


至于原理呢,简单一句话:如果内存有变量链接,那么即使那块内存是闲置的,也不会被挪作他用。
回复

使用道具 举报

 楼主| 发表于 2009-8-15 16:15:26 | 显示全部楼层
主要意思是:有些新人以为创造了什么东西不管就会泄露,其实没这回事。。。只有你引用过这个东西才会泄露

-另外,点和区域比较特殊,必然产生泄漏(必须用removexxx来删除)
回复

使用道具 举报

发表于 2009-8-16 11:42:05 | 显示全部楼层
引用楼主eff于2009-08-03 08:54发表的 关于war3排泄的机制扫盲 :
任何一个变量被赋值(set xx = xx)的时候,都会使变量原来指向对象的空间引用计数-1,新的对象空间引用计数+1
(比如已知a==hero1,set a=unit1的操作会导致hero1的引用计数-1,unit1的计数+1)


嗯,如果已知a==hero1,执行set a=hero1的话会怎样?
原来指向对象和新的对象都是hero1,这样hero1的引用数是不是不变呢?
回复

使用道具 举报

 楼主| 发表于 2009-8-17 13:56:13 | 显示全部楼层
会先-1然后+1,结果没变化
回复

使用道具 举报

发表于 2009-8-18 13:19:52 | 显示全部楼层
我和小血曾经尝试的某个系统仔细的研究了排泄方面的部分问题

首先就是正确的使用unionbug会避免出现泄露,看下面的帖子就知道了
其中头目也对handle泄露做了说明。
Union Bug 1个需要注意的地方

另外我做过仔细的实验
当连接数为0时(也就是set null后)handle值并不会立即排泄
而是在当前触发结束或者遇到等待才进行的
也就是在set null后,触发继续运行中,应该被释放的handle无法继续使用
直到等待或者触发结束

unit是到触发结束才会被排泄,等待是也不会。
因此,排泄本身不是set null做的
而是当某条件达成(例如触发完成或者运行到等待),虚拟机会找到链接数为0的项
将其排泄掉

以上是LZ所说的泄露
但是我感觉这部分并不十分重要
它只会影响到handle表的释放,
也就是几个字节的问题
当然过长的handle表会降低数据读取的效率

实际上最大的泄露还是忘记删除的内容
比如Location……
(war的官方函数中都有存在Location泄露的)
类似单位位置、区域的中心……
这些函数都会创建点
当你没有用变量记录并最终使用removeLocation删除的话
他们的泄露会很大……
至少一个实体泄露在内存占用量上等于多个handle空位的……
一般的WEer主要考虑的就是这部分泄露

最后的泄露就是string泄露
这个是无可避免的
不过如果不使用GC的话
可以不考虑……

最后发现当时的某些成果没有发布啊……
恩恩
都丢失了……
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-5-4 07:46 , Processed in 0.035118 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表