YDWE已经历经了三个版本的泄漏检测
第一个版本就是搬运了老外的jass库,原理是利用vjass的钩子来钩一些常用的函数。不过问题很多,vjass的钩子本身就很多毛病,加上原理上来说这个库只会告诉你当前已经存在哪些handle,实际上并不能告诉你哪些handle是泄漏了,哪些是正常的handle。
第二个版本是我写的。原理和老外的相同,只是从vjass的钩子改成理论YDWE的预处理来实现,并且利用YDWE的代码生成让泄漏检测库获得了获取当前触发器的触发器名的功能,以便可以更好地定位泄漏的handle的位置。不过由于原理相同,和第一个版本比只是bug变少了,其他问题依然存在。
第三个版本就是现在YDWE里的泄漏检测插件,泄漏检测插件包含两个功能,一个是第二个版本的C++移植版,使用C++做钩子速度上比Jass快了很多,但原理相同所以遇到的问题也相同;另一个是一个遍历所有handle以及列出它们的信息的功能,通过手动分析,可以解决大多数的泄漏问题。这种方式我认为是最有效和合理的泄漏检测,不过当初加这个,只是因为自用,对我而言,手动分析就足够了,但可能大多数人并搞不懂这个功能。
最近我对这个新的泄漏检测方式做了大量的优化,以便让更多的人可以使用它。同时旧的方式应该也可以退役了。那么我就来简单的说下原理。
魔兽的handle(准确地说是agent)都是由引用计数来管理,当引用计数变为0时,handle就会被释放。假如一个handle的引用计数永远也无法变为0,那么我们就可以认为这个handle已经(有)泄漏了,这就是这个泄漏检测的原理。
为了找到引用计数永远也无法变为0的handle,我们得先找到引用这个handle的地方有几处,每有一处则意味着当此处的引用被释放后,引用计数就会减一,所以问题变成了找到 “引用计数大于引用handle的数量”的handle。
对于魔兽而言,引用handle的有三种对象、变量和哈希表。所以你会看到这样的报告
handle: 0x0010005A
引用: 5
类型: trigger
对象: +trg
引用它的变量:
| gg_trg_____________u
| TEST!trg
引用它的哈希表:
| handle:0x00100048 [1][1]
这个handle有1个对象、2个变量、1个哈希表引用它,但引用计数是5,所以这个handle就有泄漏。
不过这里还有一种情况,假如0x00100048这个哈希表已经对象泄漏(也就是没有任何变量或哈希表引用者它),则意味着你永远无法把0x00100048里的东西释放掉,这实则也是泄漏了,即使这个handle的引用计数正确。暂时我认为这种情况还是你自己手动分析比较好。
以上这种被称为handle泄漏,handle泄漏是写Jass的人最容易犯的错误,因为魔兽有个坑爹的bug,函数参数的handle不会自己释放引用。即使是暴雪自己写的代码(blizzard.j)也包含着大量的泄漏,就是因为这个原因。不过YDWE不会去用原版的blizzard.j,所以写T的人很少会遇到这个问题,但写J就很常见了。
还有一种泄漏是对象泄漏,如果一个handle没有被任何变量和哈希表引用,但被对象引用,这个就是对象泄漏。但并不是所有的对象泄漏都是泄漏,有些对象泄漏是正常的。对象泄漏的实际含义是,我们无法通过变量或者哈希表的手段来获取这个对象。但是有可能我们还有别的手段获取它,比如1.20时代的gamecache,还有像单位我们虽然没有变量记录者它,但我们依然可以用选取的方式来找到这个单位,在这种情况下,它并不算泄漏。
最后一种情况是,泄漏但实则无所谓的。例如player,在魔兽里player总是固定的16个,这16个handle引用或者不引用,其实都是无所谓的。
第一个版本就是搬运了老外的jass库,原理是利用vjass的钩子来钩一些常用的函数。不过问题很多,vjass的钩子本身就很多毛病,加上原理上来说这个库只会告诉你当前已经存在哪些handle,实际上并不能告诉你哪些handle是泄漏了,哪些是正常的handle。
第二个版本是我写的。原理和老外的相同,只是从vjass的钩子改成理论YDWE的预处理来实现,并且利用YDWE的代码生成让泄漏检测库获得了获取当前触发器的触发器名的功能,以便可以更好地定位泄漏的handle的位置。不过由于原理相同,和第一个版本比只是bug变少了,其他问题依然存在。
第三个版本就是现在YDWE里的泄漏检测插件,泄漏检测插件包含两个功能,一个是第二个版本的C++移植版,使用C++做钩子速度上比Jass快了很多,但原理相同所以遇到的问题也相同;另一个是一个遍历所有handle以及列出它们的信息的功能,通过手动分析,可以解决大多数的泄漏问题。这种方式我认为是最有效和合理的泄漏检测,不过当初加这个,只是因为自用,对我而言,手动分析就足够了,但可能大多数人并搞不懂这个功能。
最近我对这个新的泄漏检测方式做了大量的优化,以便让更多的人可以使用它。同时旧的方式应该也可以退役了。那么我就来简单的说下原理。
魔兽的handle(准确地说是agent)都是由引用计数来管理,当引用计数变为0时,handle就会被释放。假如一个handle的引用计数永远也无法变为0,那么我们就可以认为这个handle已经(有)泄漏了,这就是这个泄漏检测的原理。
为了找到引用计数永远也无法变为0的handle,我们得先找到引用这个handle的地方有几处,每有一处则意味着当此处的引用被释放后,引用计数就会减一,所以问题变成了找到 “引用计数大于引用handle的数量”的handle。
对于魔兽而言,引用handle的有三种对象、变量和哈希表。所以你会看到这样的报告
handle: 0x0010005A
引用: 5
类型: trigger
对象: +trg
引用它的变量:
| gg_trg_____________u
| TEST!trg
引用它的哈希表:
| handle:0x00100048 [1][1]
这个handle有1个对象、2个变量、1个哈希表引用它,但引用计数是5,所以这个handle就有泄漏。
不过这里还有一种情况,假如0x00100048这个哈希表已经对象泄漏(也就是没有任何变量或哈希表引用者它),则意味着你永远无法把0x00100048里的东西释放掉,这实则也是泄漏了,即使这个handle的引用计数正确。暂时我认为这种情况还是你自己手动分析比较好。
以上这种被称为handle泄漏,handle泄漏是写Jass的人最容易犯的错误,因为魔兽有个坑爹的bug,函数参数的handle不会自己释放引用。即使是暴雪自己写的代码(blizzard.j)也包含着大量的泄漏,就是因为这个原因。不过YDWE不会去用原版的blizzard.j,所以写T的人很少会遇到这个问题,但写J就很常见了。
还有一种泄漏是对象泄漏,如果一个handle没有被任何变量和哈希表引用,但被对象引用,这个就是对象泄漏。但并不是所有的对象泄漏都是泄漏,有些对象泄漏是正常的。对象泄漏的实际含义是,我们无法通过变量或者哈希表的手段来获取这个对象。但是有可能我们还有别的手段获取它,比如1.20时代的gamecache,还有像单位我们虽然没有变量记录者它,但我们依然可以用选取的方式来找到这个单位,在这种情况下,它并不算泄漏。
最后一种情况是,泄漏但实则无所谓的。例如player,在魔兽里player总是固定的16个,这16个handle引用或者不引用,其实都是无所谓的。