魔兽地图编辑器吧 关注:64,841贴子:3,834,002

【科普+预告】泄漏检测

只看楼主收藏回复

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引用或者不引用,其实都是无所谓的。


IP属地:广东1楼2018-10-21 21:36回复
    学习了


    应用达人
    应用吧活动,去领取
    活动截止:2100-01-01
    去徽章馆》
    IP属地:辽宁来自Android客户端2楼2018-10-21 21:49
    回复


      来自手机贴吧3楼2018-10-21 21:55
      回复
        原来参数也不会自动释放。。。是谁告诉我说参数会自动释放的。。。


        IP属地:福建来自Android客户端4楼2018-10-21 22:08
        回复(2)
          dalao


          IP属地:湖南5楼2018-10-21 22:32
          回复


            IP属地:广东7楼2018-10-22 00:06
            回复
              预告?是又要更新这方面的吗


              IP属地:北京来自Android客户端8楼2018-10-22 01:26
              回复
                滋瓷


                IP属地:湖北来自Android客户端9楼2018-10-22 08:13
                回复
                  所以泄漏检测功能马上不再是“不推荐使用”分类了吗


                  IP属地:浙江来自iPhone客户端10楼2018-10-22 09:45
                  回复
                    真高产。


                    11楼2018-10-22 18:57
                    回复
                      通过ref的方式找泄漏确实是合理的方式。那么有考虑过在此基础上实现自动排泄j实现的可能性?我的意思是j党由于“菜”的原因没有正确的在代码中排泄,是不是可以考虑引入一个自动排泄的功能?


                      IP属地:上海12楼2018-10-22 22:58
                      回复
                        类似于unref这样的函数,就比如LoadLibrary这个函数在模块已经加载的情况下只会增加一个引用计数,相对的,有几次Load就应该有几次Free,这个概念在SuspendThread和ResumeThread也有。无论在应用层还是内核层也都有通过置零引用计数的方式去释放模块、释放文件句柄、杀死进程等等。那么魔兽是不是也能实现这一点?


                        IP属地:上海13楼2018-10-22 23:05
                        收起回复


                          IP属地:广东14楼2018-10-22 23:07
                          回复
                            我只关心什么时候用得上,同问参数问题。多年来破吧都是流传参数不用set null的。求一个答案


                            IP属地:广东来自iPhone客户端15楼2018-10-23 01:13
                            收起回复
                              排泄不就行了


                              16楼2018-10-24 08:50
                              收起回复