本文将介绍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:\windows\system32\vsjitdebugger.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),一般用在测试中。  

  使用示例;

  

     base::debug::StackTrace trace;
std::ostringstream os;
trace.OutputToStream(&os);
std::string backtrace_message = os.str();
std::cout << backtrace_message << std::endl;
std::cout << trace.ToString() << std::endl;
size_t frames_found = ;
trace.Addresses(&frames_found); {
base::debug::StackTrace trace;
std::ostringstream os;
trace.OutputToStream(&os);
std::cout << os.str() << std::endl;
}
 std::map<std::string, std::string>* key_values_ = NULL;

 class CrashLoggingTest
{
public:
CrashLoggingTest()
{
key_values_ = new std::map<std::string, std::string>;
base::debug::SetCrashKeyReportingFunctions(
&CrashLoggingTest::SetKeyValue,
&CrashLoggingTest::ClearKeyValue);
} virtual ~CrashLoggingTest()
{
base::debug::ResetCrashLoggingForTesting(); delete key_values_;
key_values_ = NULL;
} private: static void SetKeyValue(const base::StringPiece& key,
const base::StringPiece& value)
{
(*key_values_)[key.as_string()] = value.as_string();
} static void ClearKeyValue(const base::StringPiece& key)
{
key_values_->erase(key.as_string());
}
}; CrashLoggingTest crashLog; const char* kTestKey = "test-key";
base::debug::CrashKey keys[] = { { kTestKey, } };
base::debug::InitCrashKeys(keys, arraysize(keys), ); base::debug::SetCrashKeyValue(kTestKey, "value");
bool res = false;
res = "value" == (*key_values_)[kTestKey]; base::debug::ClearCrashKey(kTestKey);
res = (key_values_->end() == key_values_->find(kTestKey)); key_values_->clear();
delete key_values_;

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

   使用方式比较简单,如:

  

 class A
{
// ...
private:
base::LeakTracker<A> leak_tracker_;
};

  此后通过调用 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中移除本对象实例;

  使用示例:

  

 class ClassA
{
private:
LeakTracker<ClassA> leak_tracker_;
}; bool res = false;
int num = LeakTracker<ClassA>::NumLiveInstances(); // num == -1; ClassA a1;
num = LeakTracker<ClassA>::NumLiveInstances(); // num == 1
scoped_ptr<ClassA> a2(new ClassA);
num = LeakTracker<ClassA>::NumLiveInstances(); // num == 2
a2.reset();
num = LeakTracker<ClassA>::NumLiveInstances(); // num == 1 LeakTracker<ClassA>::CheckForLeaks();// leaks!!!

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

Google之Chromium浏览器源码学习——base公共通用库(四)的更多相关文章

  1. Google之Chromium浏览器源码学习——base公共通用库(二)

    上次提到Chromium浏览器中base公共通用库中的内存分配器allocator,其中用到了三方库tcmalloc.jemalloc:对于这两个内存分配器,个人建议,对于内存,最好是自己维护内存池: ...

  2. Google之Chromium浏览器源码学习——base公共通用库(三)

    本节将介绍base公共通用库中的containers,其包含堆栈.列表.集合.以及Most Recently Used cache(最近使用缓存模板). linked_list.h:一个简单的列表类型 ...

  3. Google之Chromium浏览器源码学习——base公共通用库(一)

    Google的优秀C++开源项目繁多,其中的Chromium浏览器项目可以说是很具有代表性的,此外还包括其第三开发开源库或是自己的优秀开源库,可以根据需要抽取自己感兴趣的部分.在研究.学习该项目前的时 ...

  4. Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析

    经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...

  5. Golang源码学习:调度逻辑(四)系统调用

    Linux系统调用 概念:系统调用为用户态进程提供了硬件的抽象接口.并且是用户空间访问内核的唯一手段,除异常和陷入外,它们是内核唯一的合法入口.保证系统的安全和稳定. 调用号:在Linux中,每个系统 ...

  6. Java并发包源码学习之AQS框架(一)概述

    AQS其实就是java.util.concurrent.locks.AbstractQueuedSynchronizer这个类. 阅读Java的并发包源码你会发现这个类是整个java.util.con ...

  7. [tomcat7源码学习]初始化之catalina.home和catalina.base(转)

    我们在代码中为了获取某个配置文件路径下的文件经常会这么写 String tomcatPath = System.getProperty("catalina.home") + &qu ...

  8. Tomcat源码学习

    Tomcat源码学习(一) 转自:http://carllgc.blog.ccidnet.com/blog-htm-do-showone-uid-4092-type-blog-itemid-26309 ...

  9. 【 js 基础 】【 源码学习 】源码设计 (持续更新)

    学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析第二部分:undersc ...

随机推荐

  1. 微信JSSDK javascript 开发 代码片段,仅供参考

    最全面最专业的微信公众平台开发教程:http://www.cnblogs.com/txw1958/p/weixin-js-sdk-demo.html 比较完整的分享教程:http://www.cnbl ...

  2. MySQL学习

    关于MySQL学习,先推荐一个网站,资源很多.讲得很细 StudyMySQL-最好的MySQL学习网站 我的MySQL学习之旅: 1.简单了解下MySQL数据库,安装MySQL.MySQL管理工具(刚 ...

  3. Internet Download Manager 6.27.1 中文特别版(IDM)

    软件介绍: 软件名称:Internet Download Manager(IDM) 软件大小:5.09M软件语言:简体中文 软件官网:http://www.internetdownloadmanage ...

  4. 什么是Javascript Hoisting?

    Javascript是一门容易遭人误解的语言,但是它的强大毋庸置疑.个人觉得,要想深入理解Javascript语言,首先必须对其基本的概念(例如:Scope,Closure,Hoisting等)要真正 ...

  5. 深入理解javascript原型和闭包(7)——原型的灵活性

    在Java和C#中,你可以简单的理解class是一个模子,对象就是被这个模子压出来的一批一批月饼(中秋节刚过完).压个啥样,就得是个啥样,不能随便动,动一动就坏了. 而在javascript中,就没有 ...

  6. Python 读写文件中数据

    1 需求 在文件 h264.txt 中的数据如图1,读入该文件中的数据,然后将第1列的地址删除,然后将数据输出到h264_out.txt中: 图1 h264.txt 数据截图             ...

  7. css之图片路径

    关于背景图片url路径:图片和调用文件在两个不同根下的(不在同一个包(文件夹)中),要用相对路径,举例"../images/cq.gif":图片和调用文件是在一个根下的直接孩子,用 ...

  8. Storm 单机版环境搭建

    1 需要安装的软件 要使用storm首先要安装以下工具:python.zookeeper.zeromq.jzmq.storm 1.1 安装zeromq wget http://download.zer ...

  9. 短信接口API

    /** * Created by bingone on 15/12/16. */ import org.apache.http.HttpEntity; import org.apache.http.N ...

  10. javascript数据结构与算法-- 二叉树

    javascript数据结构与算法-- 二叉树 树是计算机科学中经常用到的一种数据结构.树是一种非线性的数据结构,以分成的方式存储数据,树被用来存储具有层级关系的数据,比如文件系统的文件,树还被用来存 ...