zoukankan      html  css  js  c++  java
  • 转 GFlags 使用详解

    转载地址:https://blog.csdn.net/wl_fln/article/details/6283587

    如果你是C++程序员,如果你写过一个很复杂的程序,如果你经常碰到莫名其妙的崩溃问题。那么你就有可能遭遇了野指针。如果你比较细心,注意了Debug Output输出窗口的话,那么你就有可能注意到这样一行提示:
    HEAP:   Free   Heap   block   xxxxxxxx modified   at   xxxxxxxx  after   it   was   freed

    GFlags是Windows debug tools 工具包下的一个工具,在Windows 2000的Resource Kit中也可以找得到。用来设置一些调试属性,总体上分为3个级别System,Kernel和Image File。我们设置好Path环境变量,将其指向Debug tools工具的目录下。

    下载安装 gflags:

    http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx

    http://www.ithov.com/Soft/system/systest/38210.shtml

    GFlags 

    - 老牌的PageHeap配置工具,有命令行和GUI两种操作方式,功能比较全,包含在Windbg调试器安装包内。同样在Windows 2000 Professional SP2 以上可用。

    一些使用GFlags命令行的例子:

    配置正常页堆:

    "C:/Program Files/Debugging Tools for Windows (x86)/gflags.exe" /p /enable qq.exe

    配置完全页堆:

    "C:/Program Files/Debugging Tools for Windows (x86)/gflags.exe" /p /enable qq.exe /full

    列出当前启动了页堆的进程列表:

    "C:/Program Files/Debugging Tools for Windows (x86)/gflags.exe" /p

    取消页堆设置:

    "C:/Program Files/Debugging Tools for Windows (x86)/gflags.exe" /p /disable qq.exe

    一些特殊选项解释:

    /unaligned

    这个选项只能用于完全页堆。当我们从普通堆管理器分配一块内存时,内存总是8字节对齐的,页堆默认情况下也会使用这个对齐规则,但是这会导致分配的内存块的结尾不能跟页边界精确对齐,可能存在0-7个字节的间隙,显然,对位于间隙范围内的访问是不会被立即发现。更准确的说,读操作将永远不能被发现,写操作则要等到内存块释放时校验间隙空间内的填充信息时才发现。/unaligned用于修正这个缺陷,它指定页堆管理器不必遵守8字节对齐规则,保证内存块尾部精确对齐页边界。

    需要注意的是,一些程序启用这个选项可能出现异常,例如IE和QQ就不支持。

    /backwards

    这个选项只能用于完全页堆。这个选项使得分配的内存块头部与页边界对齐(而不是尾部与边界对齐),通过这个选项来检查头部的访问越界。

    /debug

    指定一启动进程即Attach到调试器,对于那些不能自动生成dump的程序,是比较有用的选项。

    完全页堆:

        当分配一块内存时,通过调整内存块的分配位置,使其结尾恰好与系统分页边界对齐,然后在边界处再多分配一个不可访问的页作为保护区域。这样,一旦出现内存读/写越界时,进程就会Crash,从而帮助及时检查内存越界。

    因为每次分配的内存都要以这种形式布局,尤其对于小片的内存分配,即使分配一个字节,也要分配一个内存页,和一个保留的虚拟内存页(注意在目前的实现中,这个用作边界保护区域的页从来不会被提交)。这就需要大量的内存,到底一个进程需要多少内存,很难估算,因此在使用Page Heap前,至少保证你的机器至少设置了1G虚拟内存以上。

    正常页堆

        正常页堆原理与CRT调试内存分配函数类似,通过分配少量的填充信息,在释放内存块时检查填充区域。来检测内存是否被损坏,此方法的优点是极大的减少了内存耗用量。缺点是只能在释放块时检测,不太好跟踪出错的代码位置。

    页堆能处理的错误类型:

    错误类型                    正常页堆               整页堆

    堆句柄无效                     立即发现                 立即发现

    堆内存块指针无效               立即发现                 立即发现

    多线程访问堆不同步             立即发现                 立即发现

    假设重新分配返回相同地址(realloc)  90% 内存释放后发现   90% 立即发现

    内存块重复释放                 90% 立即发现             90% 立即发现

    访问已释放的内存块             90% 在实际释放后发现     90% 立即发现

    访问块结尾之后的内容           在释放后发现             立即发现

    访问块开始之前的内容           在释放后发现             立即发现

    以下是举例:

    前期工作: 将gflags(默认安装在C:/Program Files/Debugging Tools for Windows (x86))加入到path

    案例1:
    int _tmain(int argc, _TCHAR* argv[])
    {
         char *p = new char[8];
         p[8] = 10;

         delete[] p;
         return 0;
    }
    程序本身是有问题的。数组已经越界,但是debug模式下并不报错,release模式下也很大可能是不crash的。

    在命令提示符下运行:

    >gflags /p /enable test.exe /full

    在release模式运行test.exe。exception将直接定位到 p[8] = 10; 这一行

    案例2:
    int _tmain(int argc, _TCHAR* argv[])
    {
         char *p = new char[9];
         p[9] = 10;

         delete[] p;
         return 0;
    }
    以上代码和案例1仅有一点不同,就是数组大小。但是如果运行
    gflags /p /enable test.exe /full

    在release模式下并不会出现exception并定位到 p[9] = 10;
    原因是没有设置 /unaligned 参数,具体看说明。案例2中,数组有9字节大小,按内存8字节对齐的说法,这块内存应该是

    16字节,后面还有7字节的空间,所以 p[9] = 10; 并不会产生exception。设置 /unaligned 参数,禁止8字节对齐,就

    可以跟踪到 p[9] = 10; 这个exception

    >gflags /p /enable test.exe /full /unaligned

    案例3:
    class A
    {
    public:
     int a;
     void del(){
      delete this;
      a = 10;
     }
    };
    int _tmain(int argc, _TCHAR* argv[])
    {
     A* a = new A();
     a->del();
     return 0;
    }

    在debug模式下可能产生exception:
    HEAP:   Free   Heap   block   xxxxxxxx modified   at   xxxxxxxx  after   it   was   freed
    在release模式下运行并不报错,但是程序本身是有问题的,delete this; 之后,又给成员变量 a=10;

    这显然是不对的。

    >gflags /p /enable test.exe /full
    此时在debug下运行程序,会产生exception,并定位到   a = 10;

    //----------------------------------------------------------------------------------------------------------------

    1. 安装:Debugging Tools for Windows (x86) ;

    2. 开启gflags: gflags -p /enable ***.exe /full。 “***.exe”为需要调试的进程名,不需要绝对路径。

    3. 启动要调试的程序,当执行异常操作后,VS这才变聪明了,直接指定到了直接导致异常的代码处。顿时,晴空万里。

     启动了gflags,调试运行就慢了,比较它要变聪明要学习足够的东西。It's the same to ourselves.

     不使用gflags时:

     gflags -p /disable ***.exe
    ---------------------
    作者:vileyking
    来源:CSDN
    原文:https://blog.csdn.net/wl_fln/article/details/6283587
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    js正则表达式中的问号使用技巧总结
    380. Insert Delete GetRandom O(1)
    34. Find First and Last Position of Element in Sorted Array
    162. Find Peak Element
    220. Contains Duplicate III
    269. Alien Dictionary
    18. 4Sum
    15. 3Sum
    224. Basic Calculator
    227. Basic Calculator II
  • 原文地址:https://www.cnblogs.com/bodboy/p/10535273.html
Copyright © 2011-2022 走看看