- 博客(98)
- 资源 (10)
- 收藏
- 关注
原创 里氏替换原则(LSP)
里氏替换原则(英文名为Liskov substitution principle,简称LSP)是由Barbara Liskov在1988年提出的,在Robert C. Martin提出的SOLID软件设计原则中的第二个字母L。挑出一个相对比较容易明白的定义:if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of t
2022-05-15 17:41:06 1601
原创 C++类库隐藏私有属性和方法的两种方式
在我们编写程序的时候,会将程序模块化,常见的就是用动态链接库的方式,然后导出函数接口或者类。而对于导出类的方式,作为模块的实现者,不论是给第三方使用或者自己的项目使用,应该都不太愿意暴露自己的私有属性和方法,个人碰到的主要有以下两个常见原因:通过隐藏私有属性和方法,让被调用者猜不到其实现方式私有方法中或者属性中,可能会存在一些第三方的头文件或者库的依赖,而对于被调用方来说不应该直接依赖本文将介绍两种方式来满足以上的需求,一种是...
2022-05-08 18:15:08 2192
原创 单一职责原则(SRP)
什么是单一职责原则单一职责原则(英文名为Single Responsibility Principle,简称SRP)是Robert C. Martin提出的SOLID软件设计原则中的第一个字母S。Robert C. Martin给出的定义为, 有且仅有一个原因导致类的变化。A class should have one, and only one, reason to change.而本人更偏向于Wiki上对SRP的描述, 其单一职责原则应该运用于模块, 类以及文件。The single-r
2022-05-01 16:14:19 5854 2
原创 设计模式之简单工厂,工厂方法和抽象工厂
在面向对象的编程中,一般通过继承和虚函数来提供抽象能力,多态让程序在执行期,调用者只需要看到父类类型,而不需要关心继承的子类类型。举个例子: 比如有个游戏,里面的游戏的活动对象为动物,比如有老虎和猫,会对主人公进行攻击。那么可能会实现为如下:代码如下:class Animal{public: virtual void Attack() = 0;};class Tiger : public Animal{public: virtual void Attack() { std::cout
2022-01-03 21:26:07 2833
原创 GoReplay进阶之插件实现
GoReplay神器最有效的功能就是在基本不影响线上服务机器运行的情况下,非侵入式地将真实流量导入到本地磁盘文件或者测试机器,实现测试机器上采用真实流量进行测试,从而保证产品发布的质量。在上一篇文章<<HTTP流量拷贝测试神器GoReplay>>, 笔者主要对以下四个方面进行了描述。流量复制测试流量保存到文件和重放功能介绍HTTP请求过滤HTTP请求更改但是我们可能还会碰到如下问题:流量测试结果对比:这个是指,比如即将发布新的程序,将其测试结果和原先的版本测试结果
2021-11-27 20:10:20 1416
原创 HTTP流量拷贝测试神器GoReplay
一般在软件发布之前,都会经过单元测试, 接口测试, 集成测试, 性能测试等。但是这些测试往往都是基于自己定义的测试数据集合,很可能会有漏网之鱼,那么在软件上线之后,在线上的流量冲击下,会出现各种之前测试中并没有发现的问题。这是因为线上的流量数据比测试的数据更加多样性,并且随着用户数量的增加,线上流量的也越来越大,更多的隐藏问题也会明显暴露,比如并发处理不当导致的Crash也随之出现。 那么我们有什么方法能够在上线之前完成这些测试呢?有的,那就是GoReply。GoReply概述当前越来越多的产品SaaS
2021-11-20 16:16:34 2943
原创 谈谈多例模式(multiton)的使用
之前的文章<<谈谈单例模式>>介绍过单例模式, 其全局只会生成一个实例化的对象。当初采用的是全局配置文件的实践案例, 因为比较适合采用单例模式。设计模式是前辈们通过丰富的工程实践后总结出的经验。所以笔者认为对于设计模式的理解,并不仅仅在于看懂这个模式的实现方式,更重要的是明白什么时候该使用什么设计模式,而要做到这个,离不开的是不断地实践。注意这里的实践,并不是说手写一遍设计模式的实现,而是多做一些项目,从项目中汲取经验,才能理解的更加深刻,变为自己能够灵活运用的知识。而本文也将从
2021-10-22 20:43:38 1129
原创 Lambda表达式
常见的语言中都提供Lambda语法糖,比如C#, Python, Golang等。本文将探讨下C++ 11引入的Lamdba语法糖。语法糖是一种让程序员使用更加便利的一种语法,并不会带来额外的功能,比如Lambda,没有这种语法糖,其可以用已有的语法等价的实现出相应的功能。有编程实践经验的同学一定能够快速的理解Lamdba产生的意义,而缺乏编程经验的同学,跟着我一起来梳理下Lamdba给我们带来了哪些便利性?函数指针和对象函数因为笔者用Lambda最多的场景是回调函数,先说说回调函数。在编程中回调函数
2021-10-04 21:53:09 571 1
原创 谈谈单例模式
单例模式是一个很常见的设计模式,也广泛应用于程序开发。其具有如下特点:一个类只有一个实例化对象全局可以使用那么有人要问,那我不就定义一个类,程序只初始化一个全局的实例就好了吗? 没错,这样是可以的。但是我们都知道程序会经过多人的接手维护和开发,比如第N个接手程序的时候,并不知道这个类定义的时候只能初始化一个实例,然后又实例化了新的对象, 则可能会造成意想不到的场景。那么这时候就要提到防御性编程,个人认为单例模式的实现也是防御性编程的一种方式,让这个类保证只有一个实例化对象,并且如果试图构造多个对象
2021-09-19 20:09:15 367
原创 插件式开发架构综述
投稿者: 地下潜行者1. 概述在现有软件开发中,业务越来越复杂,代码规模越来越大,依赖的人力也越来越多。为了降低系统模块内部耦合度,减少开发难度,也为了能够支持多团队的并行开发,插件式开发架构变得愈加流行,尤其是在桌面软件、移动端应用中。对于后端开发,微服务的形式也越来越流行,但是据笔者看来,微服务的很多设计思路,和插件式开发架构的设计理念也有相近之处。Eclipse, Visual Studio, VSCode等,都是插件式开发架构的典型案例。现代软件提供插件式开发架构,一方面是服务于产品自身内部开
2021-09-05 12:00:43 4857
原创 对象池的使用场景以及自动回收技术
对象池在编程中,我们经常会涉及到对象的操作,而经常的操作模式如下图所示:创建对象->使用对象->销毁对象。而这个对象有可能创建的时候会需要构建很多资源,消耗比较大, 比如:在hiredis的SDK中每次都创建一个redisContext,如果需要查询,那就首先要进行网络连接。如果一直都是上图的工作方式,那将会频繁的创建连接,查询完毕后再释放连接。重新建立连接,让网络的查询效率降低。这个时候就可以构建一个对象池来重复利用这个对象,并且一般要做到线程安全:从对象池中获取对象,如果没有对象
2021-08-29 21:31:35 1111
原创 Protobuf用过没?
一个故事在读书的时候,参与的第一个是实质性的项目,其中有一部分网络通信,基于socket编程。网络通讯TCP/IP相当于交通工具,上层应用协议还得自己设计。 学过计算机网络这门课的,自然会对所学的知识举一反三。首先查看一个TCP的协议格式:protobuf,语言之间的内容传递,进程间通信。protobuf 2 vs 3json vs protobuf参考<>...
2021-08-23 22:33:45 360
原创 你踩过几种C++内存泄露的坑?
在`Modern C++`之前,C++无疑是个更容易写出坑的语言,无论从开发效率,和易坑性,让很多新手望而却步。比如内存泄露问题,就是经常会被写出来的坑,本文就让我们一起来看看,这些让现在或者曾经的`C++`程序员泪流满面的`内存泄露`场景吧。你是否有踩过?
2021-08-16 12:05:25 762
原创 Windows C++堆破坏场景及分析
一个堆破坏的老故事还记得第一次碰到堆破坏的时候,大概十年前了,当时在学校开发一个Wireshark插件,可是有一个问题我久久未能解决: 我修改后的Wireshark运行的时候偶尔启动的时候会出现程序崩溃,那时候也不会用Windbg, 后来用Visual Studio启动Wireshark, 也是偶尔报错,这个时候可以看到堆栈,只记得当时是在一个很正常的内存分配或者释放的时候出现崩溃。那么总结为两点:偶尔重现,那么也就是我们常说的还能跑起来,跑不起来那么就重启进程,重启进程无效,那就万能方法重启机器。这
2021-08-08 14:34:20 3287 3
原创 基于消息的事件驱动机制(Message Based, Event Driven)
投稿者: 地下潜行者1. 基本模型概述基于消息的事件驱动机制是一个通用模型,广泛应用于桌面软件开发、网络应用程序开发、前端开发等技术方向中。本文主要描述基本模型、基本框架,用于说明不同技术的共性知识。可以理解为外部操作事件,被转化为消息存放于队列中;而每种类型的消息都有对应的处理;通过消息循环,完成读消息、调用消息处理这个过程。这个过程,只要应用不退出,会一直进行下去。下图的模型从Windows应用程序而来,但是具有一定的通用性。2. 模型在MFC程序中的应用MFC(Microsoft Found
2021-08-01 19:09:41 762
原创 谈一谈Windows中的堆
如果在Windows中编程应该了解一些Windows的内存管理,而堆(Heap)也属于内存管理的一部分。Windows Heap下图参考<<Windows高级调试>>所画,并做了一些小小的修改。可以看出来程序中对堆的直接操作主要有三种:进程默认堆。每个进程启动的时候系统会创建一个默认堆。比如LocalAlloc或者GlobalAlloc也是从进程默认堆上分配内存。你也可以使用GetProcessHeap获取进程默认堆的句柄,然后根据用这个句柄去调用HeapAlloc达到在系统
2021-07-28 16:02:53 2200
原创 C++常见的三种内存破的场景和分析
有一定C++开发经验的同学大多数踩过内存破坏的坑,有这么几种现象:比如某个变量整形,在程序中只可能初始化或者赋值为1或者2, 但是在使用的时候却发现其为0或者其他的情况。对于其他类型,比如字符串等,可能出现了一种出乎意料的值!程序在堆上申请内存或者释放内存的时候,在内存充足的情况下,居然出现了堆错误。当出现以上场景的时候,你该思考一下,是不是出现了内存破坏的情况了。而本文主要通过展示和分析常见的三种内存破坏导致覆盖相邻变量的场景,让读者在碰到类似的场景,不至于束手无策。而对于堆上的内存破坏,很常见并
2021-07-18 21:45:30 1272 1
原创 从一个单元测试用例来说说编程中的编码问题
在编程中,大多数程序员都离不开编码问题: 系统的默认区域和语言设置,代码文件的编码,以及代码中字符串的编码。编码简述以及Windows默认配置一提到编码大家最熟悉的莫过于ASCII(American Standard Code for Information Interchange), 其采用7个bit表示128个字符,包含了常见的英文字符、数字,控制字符等。 但是ASCII不包含中文,日文等文字的编码,便出现了针对中文的编码GB2312,GBK等编码,针对日文的Shift_JIS编码,他们都兼容ASC
2021-07-10 17:38:59 551 2
原创 C++ RAII实现golang的defer
在之前一篇文章<<从lock_guard来说一说C++中常用的RAII>> 讲解了RAII, 其实一种常见的资源管理方式,减少了资源泄露的风险。 同事和我说是不是就是智能指针, 准确来说RAII是一种思想,一般是利用栈上对象初始化进行资源的申请,在其生命周期结束的时候,自动调用其析构函数,对资源进行释放。 比如std::string, std::lock_guard都属于RAII的一种实现,那么对于不同资源的管理我是否都要实现一个类似于std::lock_guard一样的实现,其实不
2021-06-26 19:06:13 644 1
原创 微软Debug CRT库是如何追踪C++内存泄露的?
本人在之前已经写过四篇关于Windows中如何查找内存泄露的方法,基本上可以说可以帮你找到内存泄露的问题所在。<<Windows内存泄露分析之DebugDialog>><<Windows程序内存泄漏(Memory Leak)分析之Windbg>><<Windows程序内存泄漏(Memory Leak)分析之UMDH>><<vmmap分析内存泄露问题>>那么为什么要写这篇文章呢?本人在逛知乎的时候,
2021-06-11 21:32:52 451
原创 vmmap分析内存泄露问题
vmmap是sysinternals工具集中的一个工具,主要用于分析一个进程的虚拟内存和物理内存的使用情况。更有效的是,可以通过对比两个不同时间的内存使用情况的Snapshot,来查找内存泄露问题。vmmap介绍当你用vmmap去查看一个正在运行的进程的时候。可以看到如下图,不同类型的内存使用采用不同的颜色标明。VMMap主要列举了以下几种类型的内存使用情况:Free: 图中显示137434599232K,是不是被吓到了。这个一般是指虚拟地址空间。每个进程都有自己的虚拟地址空间,比如32位的一般为4
2021-06-02 07:26:36 3819 3
原创 一致性HASH算法研究
一致性HASH算法研究投稿者: 地下潜行者1.引言 在研究分布式存储Ceph的CRUSH算法时,看到文章介绍它是一种特殊的一致性HASH算法,于是我便开始研究一致性HASH算法,做先期准备,发现理念确实接近,所以先研究一致性HASH算法的实现思路。2.一致性HASH的出现背景及其优势 在分布式系统中,常常利用HASH算法进行数据分布,使得海量数据均匀的分布在不同的缓存服务器上,目的是希望将数据均匀的分布到各节点,分担压力,尤其是在缓存系统中。一个典型的设计如下:2
2021-05-21 07:26:28 284
原创 栈上内存溢出漏洞利用之Return Address
程序员大多都碰到过栈上内存溢出溢出,最常见的结果是导致程序Crash,有时候也有可能因为覆盖栈上的信息导致程序执行一些意想不到的逻辑,这种情况往往比起Crash更加糟糕。在阅读本文之前,最好熟悉<<你了解函数调用过程吗?>> 文章的讲解: 以32位程序为例,讲解了函数调用是如何利用栈的。局部变量存放在栈上,而当局部变量是一个数组,那么在操作过程中就很容易发现溢出问题,即读/写数据操作了其空间。在大多数系统中,栈默认是由高地址向低地址扩展,并且在小端机器中低位在低地址,如果在写数组
2021-05-16 22:25:57 7842 1
原创 栈溢出场景的分析(2)
在上一篇文章<<栈溢出的场景分析和建议>>中,本人分享了如何查找程序Crash的函数调用栈,然后通过代码审查找到栈溢出的原因。但是却有一些场景通过代码审查不易找到问题,比如如下两点:函数的调用逻辑复杂,且触发逻辑依赖于输入样例。这样通过代码审查是很难看出问题所在的。当触发的栈溢出问题在非自己公司开发的第三方库中,无法获取源代码,也不易看出问题。那么针对上面这两点,都需要一个东西去做辅助分析,那就是触发栈溢出的输入内容(这的所谓输入内容不是指用户在交互界面输入,而是指触发这个
2021-05-06 22:30:37 447 1
原创 Windows内存泄露分析之DebugDialog
Windows中内存泄露的文章本人已经写过两篇<<Windows程序内存泄漏(Memory Leak)分析之UMDH>>和<<Windows程序内存泄漏(Memory Leak)分析之Windbg>>。如果有丰富调试经验的同学会发现,很难用一种工具或者方法去分析所有的场景,尤其当工程庞大的时候。本文要介绍的就是微软提供的DebugDialog, 他可以用于分析Hang,性能问题,内存泄露问题等等。对于内存泄露问题,DebugDialog分析后会给出一个完整的R
2021-05-04 13:06:31 1713
原创 栈溢出的场景分析和建议
场景介绍有时候当你收到一个dump后,大多数情况可以通过k命令查找到导致栈溢出的函数。但是本文要讲的是,曾经碰到过的栈溢出(stackoverflow), 却无法直接通过k命令查看到当前的函数调用栈。 下面将介绍一个简单的方法,找到导致栈溢出的函数。样例代码先声明下,因为产品的实际分析不能够通过网络分享。下面的样例代码,实际上不会导致在上一章场景介绍中提到的问题,可以直接通过crash的栈查找到代码,本文只是通过这个例子来讲解如下场景的分析思路: 如果栈溢出了,通过k命令却无法查找到函数调用栈。#i
2021-04-15 21:22:47 782
原创 Windows程序内存泄漏(Memory Leak)分析之Windbg
之前本人写了一篇<<Windows程序内存泄漏(Memory Leak)分析之Windbg>>。这种方法有一定的局限性:实践证明,当程序复杂,内存频繁的申请释放,通过UMDH对比的文件将会非常的大,并且很难直接看出内存泄露所在。UMDH在收集信息的需要符号文件,不太适合于在客户的机器上进行操作。调试方法很难一通百用,因为不同的工具都有自己的局限性,也有适合自己的分析场景,这个取决于碰到的问题。那么本文来介绍一种,使用Windbg分析内存泄露的方法。样例代码这个样例代码中
2021-04-04 20:42:40 1992
原创 从lock_guard来说一说C++中常用的RAII
常见问题在一个函数中(或者一个{...}作用域)有时候会创建/引用了一个资源,而在这个函数结束的时候需要对这个资源进行释放。常见的场景:申请了一段内存,退出时候需要释放打开了一个文件,退出需要关闭文件统计某个函数调用的当前引用次数,进入的时候引用加一,退出的时候引用减一某个{...}作用域开始需要加锁,执行完代码后需要解锁等等…以上面的锁为例, 在进入函数的时候加锁,在函数退出的时候解锁。这种写法笔者认为可能会带来两个问题:在互斥区的代码有可能会有多处返回return, 在每个re
2021-04-01 09:26:44 476
原创 free一个合法的地址也会导致crash?
场景描述在Windows平台上使用C++开发了一个服务,其中组合了各种各样的第三方组件,一般以lib/dll和头文件的形式使用。有这样一种场景,如下图所示,应用程序申请了一段内存ptr, 但在调用lib.dll的函数接口中其调用了free(ptr)。一般来说我们也尽量避免在一个组件中申请内存,而在另一个组件中释放,这里恰巧是一个bug导致了跨组件的内存申请和释放。那么请各位读者思考一下,这样会有问题吗?如果你是一个老司机,也许已经发现,在某些情况下会在调用free(ptr)的时候导致程序crash。
2021-03-06 21:59:18 586
原创 我的程序被谁干掉了?
终端产品一般部署在客户的环境中,那么奇奇怪怪的问题也就容易出现了。比如Windows产品进程为什么忽然停止了? 这个时候稍微有些经验的程序员会做出以下判断:中型的产品中,代码比较复杂。是不是程序中有什么退出逻辑,没有注意到?是不是程序崩溃了,比如资源不足或者代码bug?是不是系统中的其他程序关闭了我们的进程?比如客户的脚本或者其他的软件。是不是程序中有什么退出逻辑,没有注意到?这种情况一般通过Debug Log 可以进行追踪。比如常见的程序退出的时候会有Log记录。是不是程序崩溃了,比如资源
2021-01-24 13:39:34 623
原创 实现一个Windows服务
你是否想过要实现一个Windows程序,可以让它在系统启动的时候自动运行?或者后台运行,不显示界面?或者希望运行的时候能够方便的指定权限?那么Windows服务可以满足你的需求。本文主要介绍如何用C++编写一个具有监测功能的Windows服务。先根据以下三点进行讲解:Windows服务是如何管理和运行的?如何实现和使用Windows服务?如何实现一个具有监测功能的Windows服务?Windows服务控制管理器Windows控制服务管理器(Service Control Manager)主要
2021-01-17 09:00:51 2084
原创 你了解函数调用过程吗?
函数调用是编程语言都有的概念,也许你听说过函数调用栈,但是大家都知道函数调用是如何完成的吗?我们为什么要了解这个过程:对于程序运行机制中的数据结构和实现的了解,对自己开发程序有着启发作用碰到一些疑难杂症的时候,比如函数栈溢出了或者函数栈破坏了,如何从蛛丝马迹中寻找问题的原因。了解栈溢出可能带来的危害,黑客也许会利用栈溢出的漏洞进行攻击。这篇博文我们一起来对函数调用的过程进行探究。程序样例下面是这篇博文要用到的一个样例程序:程序在main中调用了FunAdd函数。本篇就先来研究一下:函数的
2021-01-03 09:17:48 835
原创 句柄泄露问题追踪
无论是在编写Windows程序还是Linux程序,都可能存在句柄泄露的问题。在Linux中一般来说一个进程的fd使用是有上限的,可以使用ulimit命令进行上限查看,当出现fd泄露的时候,可能会出现socket创建失败,文件打不开等问题。Windows类似,本文主要阐述了对Windows中的句柄泄露的追踪方法。Windows句柄泄露在Windows开发中,当调用Windows API,比如CreateFile, CreateEvent, CreateThread 等API的时候,都会返回一个句柄Hand
2020-12-27 10:52:00 2092
原创 Windows程序内存泄漏(Memory Leak)分析之UMDH
小木发现线上的程序通过任务管理器发现内存不断的增长,怀疑是不是内存泄漏呢?用户态内存泄漏可能是句柄泄漏,堆内存泄露,Socket, GDI对象等等。而对于C++程序员来说,碰到最多的无疑是堆内存泄露:也就是通过malloc或者new从堆上申请的内存,使用完成后,并没有释放,导致程序使用的内存越来越多。小木找到了一个分析利器UMDH: 这也是Windbg工具集中的其中一个利器,它可以在一个时间点记录程序的当前程序使用的堆内存申请的信息,过一段时间后再记录一次程序使用的堆内存申请的信息,然后比较两次的结果来找
2020-12-13 14:57:31 1430
原创 “操作无法完成,因为其中的文件夹或文件已在另一个程序中打开”解决方法
有时候,当我们删除某个文件夹的时候,提示操作无法完成,因为其中的文件夹或文件已在另一个程序中打开。 如下图所示:这个时候我们一般会尝试如下的操作:先看看是不是有程序正在使用这个目录下的文件,比如 Visual Studio,可是,有时候我们关闭了程序后,可还是会继续提示这样的错误或者继续删除目录下的其他文件,直到发现是哪个文件无法删除,然后再想想是不是有其他程序打开了呢?如果还是找不到/想不到呢?终极方法登出账户或者重启机器,好吧,这个是万能解决方法。不过作为一个程序员应该有更加精准的方法,
2020-12-06 13:52:54 9997 1
原创 配置PDB符号文件服务
配置PDB符号文件服务器的想法刚入职的小木,前不久刚刚解决了一次crash问题《Windbg分析程序崩溃实践》。 小木没有松懈,继续进行项目代码和Debug技术的学习,同时也思考了一个问题**“产品每隔一段时间就会发布新的版本,当出现Crash问题的时候得手动去拷贝响应版本的pdb文件到本机进行调试,有没有什么方式可以实现自动化呢?”** 嗯,小木是一个合格的程序员,程序员就是致力于让重复的工作自动化。小木继续想,如果能把产品每次发布的pdb文件存储到一个服务器,就像微软的symbol server
2020-11-21 20:05:30 933 2
原创 Windbg分析程序崩溃实践
1. 项目场景本故事纯属虚构。初入职场的小木,负责维护一个博客系统,后端采用C++编写,部署在Windows服务器上。刚刚熟悉完产品的小木,接到了后台服务的报警,服务器后端偶尔会程序崩溃。刚开始小木还有点慌张,脑子里面浮现出各种问题,这个是程序的bug吗?茫茫的代码如何寻找问题?log能看到线索吗?当冷静下来后,小木忽然想起前几天看的两篇文章<<Windbg调试----Windbg入门>>和<<Windows程序Dump收集>>,还没动手过呢,正好练习练习
2020-11-15 16:55:33 2393
原创 Windbg调试----多线程控制调试
在调试程序的时候,可能经常会有这样的需求,让一个线程在特定的时候才让其开始执行或者暂停执行。比如复杂的多线程导致死锁的问题,又或者多线程中的Race Condition 导致程序执行异常等。很多时候,我们可以借助编写调试代码来达到多线程的调试,可是有些情况下调试的执行粒度是指令级别的,那么这个时候我们得借助调试利器Windbg了。本文我们将以《C/C++编程教训—-函数内静态类对象初始化非线程安全(
2017-09-03 18:29:36 3669
九种常用排序的实现和测试源码
2012-09-13
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人