• Google之Chromium浏览器源码学习——base公共通用库(四)


      本文将介绍debug调试相关的内容,包括调试器、性能分析、堆跟踪、跟踪事件等;

      alias.h:Alias函数,提供防止载微软的编译器优化某参数变量的操作,内部通过#pragma optimize("", off)与#pragma optimize("", on)来实现关闭所有的优化选项,再恢复它们到原始(或默认)的设定;事实上Alias内部未实现任何的操作。

      stack_trace.h:

      EnableInProcessStackDumping: 开启堆栈转储于控制台输出,当可用时进程将被立即停止,仅用于单元测试中且因非线程安全,仅主线调用。针对windows版本,通过调用SetUnhandledExceptionFilter来设置异常捕获函数StackDumpExceptionFilter,其内部为重定向至控制台输出;

      StackTrace:堆栈轨迹类,堆栈轨迹假如你需要打印出某个时间的调用堆栈状态,对象创建位置等,

      首先介绍私有成员变量:

      1. kMaxTraces, trace_[kMaxTraces]:堆栈踪迹最大缓冲区大小, MSDN介绍kMaxTraces应小于63,故内部取值最大为62;

      2. count_:实际有效踪迹帧数;

      3. 不带参数的构造函数StackTrace,内部调用CaptureStackBackTrace,使用当前的调用状态下的堆栈;

      4. 带参构造函数StackTrace,重载了两个版本;其中StackTrace(const void* const* trace, size_t count),通过一个已存在的堆栈轨迹指针地址创建,此外针对windows版本的还提供了StackTrace(_EXCEPTION_POINTERS* exception_pointers),由一个异常对象创建,并调用StackWalk64获取堆栈轨迹信息,内部针对32位和64位实现;

      5. Addresses:获取当前调用堆栈轨迹信息地址;

      6. PrintBacktrace、OutputToStream:打印堆栈轨迹信息至stderr标准错误输出流;

      7. ToString:获取当前堆栈轨迹、符号信息字符串;

      debugger.h:

      1. SpawnDebuggerOnProcess:提供开始注册系统级的JIT即时调试器,并将其附加到指定的进程中;可以看到内部提供跨平台的版本,微软和posix版本;微软版本通过访问注册表HKEY_LOCAL_MACHINE下SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug中的键为Debugger的值,如"C:windowssystem32vsjitdebugger.exe" -p %ld -e %ld,其中vsjitdebugger.exe为微软的VS即时调试器,参数-p %ld为将要调试的进程ID,-e %ld为可执行程序的进程ID,实际上可以指定一样的进程ID值即可,此后创建新的进程开启该调试;posix版本调用系统函数system,参数xterm -e 'gdb --pid=%u' &,也为进程ID,gdb调试工具。

      2. WaitForDebugger:等待指定的时间秒wait_seconds则返回,或设置参数silent为false时,则若调试器检查到抛出异常则进入调试;内部采用for循环次数为至多10*wait_seconds次,每次等待100毫秒,刚好wait_seconds秒,并循环检查BeingDebugged(若指定进程被attach运行于调试器时,返回值为真);

      3. BeingDebugged:提供不同版本,微软版本通过IsDebuggerPresent函数判断(判断调用进程是否由用户模式的调试器调试,实际上);其他版本细分为linux、BSD、ANDROID等版本,暂不细说明;

      4. BreakDebugger:提供不同版本,微软版本通过__debugbreak,暂停程序执行,打开调试器,进入调试模式;

      5. SetSuppressDebugUI,IsDebugUISuppressed目前用在UI界面是否测试设置的操作。

      debug_on_start_win.h:

      1. 提供了一个在开启运行程序时刻支持调试的类,仅提供Init,FindArgument静态接口实现;通过命令行的方式调试,至多等待时间60s进入调试;而对于命令行调试进程则等待被调试调用。目前其他地方或项目项目暂未使用到该类提供的功能。

      crash_logging.h:主要是提供一些用来添加一些元数据信息至上传负载,并将崩溃信息报告发送至崩溃服务器

      1. ScopedCrashKey:一个封装崩溃键的范围器,不允许赋值构造和复制拷贝,主要用来设置某对象的指定键的值并管理键值对的生命期,析构时清除该对象;内部调用SetCrashKeyValue(key, value)、ClearCrashKey(key)。

      2. CrashKey:用来被注册使用的,提供参数key_name作为崩溃键值名,max_length指定键值最大长度,若超过该长度则被截断;此外若该键值长度超过“chunk_max_length”但小于max_length,则会被拆分为多个块。

      3. g_crash_keys_:std::map<base::StringPiece, CrashKey>类型的全局变量指针,作为崩溃键名字的入口,分别为键与崩溃键值名;

      4. g_chunk_max_length_:单个块的最大长度;

      5. g_set_key_func_:用来设置键值对的函数;

      6. g_clear_key_func_:用来清理键值对的函数;

      7. kLargestValueAllowed:最大的max_length允许长度,1024字节;

      8. LookupCrashKey:查找g_crash_keys_中指定键的CrashKey;

      9. ChunkCrashKeyValue:辅助函数,主要用来给指定的键值名分块;内部现实为:直接截取value的crash_key.max_length长度的值,并按照chunk_max_length对截取的值分块保存至std::vector<std::string>中;

      10. SetCrashKeyValue:通过LookupCrashKey查找到崩溃键值名,若键值名不存在或键值名长度小于g_chunk_max_length_,则调用g_set_key_func_设置崩溃元数据中指定的键值对;否则对键值名截断并拆分为多个块,对于多余的,将通过g_clear_key_func_调用,各个块则调用g_set_key_func_设置块键。

      11. ClearCrashKey:清除g_crash_keys_中指定的崩溃键值名,处理的方式类似于SetCrashKeyValue,内部改为调用g_clear_key_func_实现清理工作; 

      12. SetCrashKeyToStackTrace:将记录的堆栈轨迹信息写入知道的崩溃键值名crash Key中;

      13. SetCrashKeyFromAddresses:针对12,分别取出记录的堆栈信息并按照空格隔开写入崩溃键值名中;

      14. InitCrashKeys:在使用崩溃键记录前需要调用的,所有需要用到的崩溃记录键都需要被注册,注册到g_crash_keys_,参数keys为崩溃键数组,count为最大记录数,chunk_max_length为单个块最大长度;

      15. ResetCrashLoggingForTesting:重置崩溃键系统,可被重新初始化(再次调用InitCrashKeys),一般用在测试中。  

      使用示例;

      

     1     base::debug::StackTrace trace;
     2     std::ostringstream os;
     3     trace.OutputToStream(&os);
     4     std::string backtrace_message = os.str();
     5     std::cout << backtrace_message << std::endl;
     6     std::cout << trace.ToString() << std::endl;
     7     size_t frames_found = 0;
     8     trace.Addresses(&frames_found);
     9 
    10     {
    11         base::debug::StackTrace trace;
    12         std::ostringstream os;
    13         trace.OutputToStream(&os);
    14         std::cout << os.str() << std::endl;
    15     }
     1 std::map<std::string, std::string>* key_values_ = NULL;
     2 
     3 class CrashLoggingTest
     4 {
     5 public:
     6     CrashLoggingTest()
     7     {
     8         key_values_ = new std::map<std::string, std::string>;
     9         base::debug::SetCrashKeyReportingFunctions(
    10             &CrashLoggingTest::SetKeyValue,
    11             &CrashLoggingTest::ClearKeyValue);
    12     }
    13 
    14     virtual ~CrashLoggingTest()
    15     {
    16         base::debug::ResetCrashLoggingForTesting();
    17 
    18         delete key_values_;
    19         key_values_ = NULL;
    20     }
    21 
    22 private:
    23 
    24     static void SetKeyValue(const base::StringPiece& key,
    25         const base::StringPiece& value)
    26     {
    27         (*key_values_)[key.as_string()] = value.as_string();
    28     }
    29 
    30     static void ClearKeyValue(const base::StringPiece& key)
    31     {
    32         key_values_->erase(key.as_string());
    33     }
    34 };
    35 
    36     CrashLoggingTest crashLog;
    37 
    38     const char* kTestKey = "test-key";
    39     base::debug::CrashKey keys[] = { { kTestKey, 255 } };
    40     base::debug::InitCrashKeys(keys, arraysize(keys), 255);
    41 
    42     base::debug::SetCrashKeyValue(kTestKey, "value");
    43     bool res = false;
    44     res = "value" == (*key_values_)[kTestKey];
    45 
    46     base::debug::ClearCrashKey(kTestKey);
    47     res = (key_values_->end() == key_values_->find(kTestKey));
    48 
    49     key_values_->clear();
    50     delete key_values_;

       leak_tracker.h:泄露跟踪者,一个用来验证一个类的所有实例是否被安全销毁的助手,在单线程使用中比较有用,若有泄露,则每个实例的内存分配将会被写入日志;在使用时ENABLE_LEAK_TRACKER宏需要定义,否则将无效且不会记录调用堆栈信息。

       使用方式比较简单,如:

      

    1 class A
    2  {
    3 //     ...
    4 private:
    5     base::LeakTracker<A> leak_tracker_;
    6 };

      此后通过调用 LeakTracker<A>::CheckForLeaks()来检查是否所有实例被销毁;对于失败时,有泄露,则每个实例的内存分配将会被写入日志。

      事实上,日志记录堆栈信息,内部采用StackTrace allocation_stack_成员记录堆栈踪迹;

      LeakTracker:模板类,继承于LinkNode,即之前我们接触的堆栈列表容器,如:template<typename T> class LeakTracker : public LinkNode<LeakTracker<T> > ;

      首先,成员变量allocation_stack_,用来记录堆栈踪迹;

      静态成员函数:

      1. instances:生成对应模板类型的static LinkedList<LeakTracker<T> > list实例,它主要用来保存所有创建的实例(实际上是保存该实例下的成员变量leak_tracker_,来达到记录实例数和是否存在的状态);

      2. CheckForLeaks:用来检测当前是否所有实例已被销毁,否则打印实例内存分配堆栈踪迹信息至日志文件,实时上针对每个实例内部只打印了三条堆栈踪迹;

      3. NumLiveInstances:得到当前存活的实例数目;

      构造函数LeakTracker:内部list->append(this),追加当前实例至静态变量list中;析构函数~LeakTracker:通过this->RemoveFromList()从list中移除本对象实例;

      使用示例:

      

     1 class ClassA
     2  {
     3  private:
     4   LeakTracker<ClassA> leak_tracker_;
     5 };
     6 
     7 bool res = false;
     8 int num = LeakTracker<ClassA>::NumLiveInstances(); // num == -1;
     9 
    10 ClassA a1;
    11 num = LeakTracker<ClassA>::NumLiveInstances(); // num == 1
    12 scoped_ptr<ClassA> a2(new ClassA);
    13 num = LeakTracker<ClassA>::NumLiveInstances(); // num == 2
    14 a2.reset();
    15 num = LeakTracker<ClassA>::NumLiveInstances(); // num == 1
    16 
    17 LeakTracker<ClassA>::CheckForLeaks();// leaks!!!

      总结:因其继承于LinkNode,之前在讨论容器部分时对LinkNode有说明,其限制条件和LeakTracker一致的:不要用相同的指针对象。

  • 相关阅读:
    3月30日
    3月29日
    3月26日
    3月24
    3月22日
    3月20日
    博弈论基础
    $burnside$引理与$pacute olya$定理
    min-max容斥
    模板
  • 原文地址:https://www.cnblogs.com/haomiao/p/4821196.html
Copyright © 2020-2023  润新知