使用Windbg动态调试目标进程的一般步骤详解
目录
1、概述
2、将Windbg附加到已经启动起来的目标进程上,或者用Windbg启动目标程序
2.1、将Windbg附加到已经启动起来的目标进程上
2.2、用Windbg启动目标程序
2.3、Windbg关联到目标进程上会中断下来,输入g命令将该中断跳过去
3、分析实例说明
4、分析测试程序的崩溃
4.1、启动程序,将Windbg附加到目标进程上
4.2、使用Windbg初步分析崩溃
4.3、找到相关模块的pdb文件,设置到Windbg中
4.4、加载pdb后查看包含完整信息的函数调用堆栈
4.5、设置C++源代码的路径,Windbg会自动跳转到源代码对应的行号上
4.6、有时需要查看函数中变量的值
4.7、使用.dump命令导出包含异常上下文的dump文件
4.8、可以在Windbg中进行断点调试
5、最后
C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础与进阶(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)https://blog.csdn.net/chenlycly/category_2276111.html 软件运行过程中发生的部分崩溃或闪退,在软件中安装的异常捕获模块是捕获不到的,这种情况下就需要尝试使用Windbg进行动态调试了。前面我们已经讲了Windbg静态分析dump文件的完整过程,今天我们就来详细讲述一下如何使用Windbg对目标进程进行动态调试。
1、概述
软件运行过程中发生的大多数崩溃或闪退,软件中安装的异常捕获模块(比如CrashRpt)都能捕获到,都会自动生成包含异常上下文的dump文件。我们只需要事后取来dump文件,然后用Windbg打开进行静态分析就可以了。
但有少部分崩溃或闪退,异常捕获模块是捕获不到的,或者是捕获到后产生了二次崩溃,没有生成dump文件,也就无法使用Windbg进行静态分析了。这个时候就需要使用Windbg的动态调试了。将Windbg附加到目标进程上,即Windbg跟着目标进程一起运行,一旦目标进程发生异常,Windbg能第一时间感知到并中断下来,就可以使用kn/kv/kp命令查看到崩溃时的函数调用堆栈,就能进行分析排查了。
其实使用Windbg进行动态调试的操作很简单,但很多刚入门的新人不太清楚,所以我们在此处以一个崩溃实例来详细介绍一下整个操作过程。
关于Windbg的下载安装及详细介绍,可以查看我之前写的文章:
Windbg使用详解https://blog.csdn.net/chenlycly/article/details/120631007 关于Windbg的命令汇总,可以查看我之前写的文章:
Windbg调试命令汇总https://blog.csdn.net/chenlycly/article/details/51711212
2、将Windbg附加到已经启动起来的目标进程上,或者用Windbg启动目标程序
要使用Windbg动态调试,要将Windbg关联到目标进程上,可以先将程序启动起来,然后将Windbg附加到目标进程上;也可以用Windbg启动目标程序。两种方式的使用场景略有区别。
2.1、将Windbg附加到已经启动起来的目标进程上
如果目标程序已经启动,则可以将Windbg附加到进程上。打开Windbg,点击菜单栏File->Attach to a Process...,如下所示:
在打开的窗口中,在进程列表中找到目标程序,点击确定,完成进程的附加:
一般后启动的进程,在进程列表最下面。
当程序发生卡死或者弹出系统报错框时,再去附加到进程可能也不晚的,也能查看到有用的信息。如果客户环境安全保密等级比较高,不能远程过去,没法使用Windbg去分析,可以在此时打开任务管理,在进程列表中找到目标进程,点击右键,在弹出的右键菜单中点击“创建转储文件”菜单项:
将进程的全dump文件导出到文件中,然后取来这个dump文件再进行分析。关于如何使用Windbg静态分析dump文件,我们之前已经讲过了,可以查看:
使用Windbg静态分析dump文件的一般步骤详解https://blog.csdn.net/chenlycly/article/details/130873143
2.2、用Windbg启动目标程序
有时程序异常崩溃发生在程序启动的过程中,在启动程序后再将Windbg附加到进程上就为时已晚了,可能程序启动时就崩溃了,根本没有机会去附加调试的。当然我们可以在程序初始化时调用MessageBox弹出模态框将程序阻塞住,给Windbg附加到进程创造时机。以前我们在讲Visual Studio附加到进程调试时,可以使用此方法。对于Windbg动态调试,不必这么做的,可以直接使用Windbg启动程序的,这样就能从程序启动时就去监测程序了。
打开Windbg,点击菜单栏File->Open Executable...,如下所示:
找到目标程序的路径打开目标程序即可。
2.3、Windbg关联到目标进程上会中断下来,输入g命令将该中断跳过去
将WIndbg附加到进程上成功,或者使用Windbg将目标程序启动起来后,Windbg会自动中断一次:
输入g命令将此次中断跳过去即可。让Windbg跟着目标进程一起跑,如果目标进程运行过程中产生了异常,则调试器Windbg会第一时间感知到,并中断下来,此时可以去查看函数调用堆栈去分析了。
至于为什么将Windbg附加到目标进程成功后会触发一个中断呢?原因是:
应用层调用DebugActiveProcess发起调试,操作系统会触发int 3中断,这个中断会分发给当前的调试器Windbg,Windbg就产生了一个中断,在Windbg中能看到ntdll!DbgBreakPoint函数的调用!
3、分析实例说明
为了讲述Windbg动态调试的完整过程,我们使用Visual Studio创建了一个基于MFC框架的对话框工程,在对话框中添加了一个测试按钮:
我们在测试按钮的相应函数中故意添加一段会崩溃的代码,如下所示:
// 添加的一段测试代码
SHELLEXECUTEINFO *pShExeInfo = NULL;
int nVal = pShExeInfo->cbSize; // 通过空指针访问结构体成员,导致崩溃CString strTip;
strTip.Format( _T("nVal=%d."), nVal );
AfxMessageBox( strTip );
代码中使用到的结构体SHELLEXECUTEINFO 定义如下:
typedef struct _SHELLEXECUTEINFOW
{DWORD cbSize; // in, required, sizeof of this structureULONG fMask; // in, SEE_MASK_XXX valuesHWND hwnd; // in, optionalLPCWSTR lpVerb; // in, optional when unspecified the default verb is choosenLPCWSTR lpFile; // in, either this value or lpIDList must be specifiedLPCWSTR lpParameters; // in, optionalLPCWSTR lpDirectory; // in, optionalint nShow; // in, requiredHINSTANCE hInstApp; // out when SEE_MASK_NOCLOSEPROCESS is specifiedvoid *lpIDList; // in, valid when SEE_MASK_IDLIST is specified, PCIDLIST_ABSOLUTE, for use with SEE_MASK_IDLIST & SEE_MASK_INVOKEIDLISTLPCWSTR lpClass; // in, valid when SEE_MASK_CLASSNAME is specifiedHKEY hkeyClass; // in, valid when SEE_MASK_CLASSKEY is specifiedDWORD dwHotKey; // in, valid when SEE_MASK_HOTKEY is specifiedunion { HANDLE hIcon; // not used
#if (NTDDI_VERSION >= NTDDI_WIN2K)HANDLE hMonitor; // in, valid when SEE_MASK_HMONITOR specified
#endif // (NTDDI_VERSION >= NTDDI_WIN2K)} DUMMYUNIONNAME; HANDLE hProcess; // out, valid when SEE_MASK_NOCLOSEPROCESS specified
} SHELLEXECUTEINFOW, *LPSHELLEXECUTEINFOW;#ifdef UNICODE
typedef SHELLEXECUTEINFOW SHELLEXECUTEINFO;
typedef LPSHELLEXECUTEINFOW LPSHELLEXECUTEINFO;
#else
typedef SHELLEXECUTEINFOA SHELLEXECUTEINFO;
typedef LPSHELLEXECUTEINFOA LPSHELLEXECUTEINFO;
#endif // UNICODE
在测试代码中定义了SHELLEXECUTEINFO结构体指针pShExeInfo,并初始化为NULL,然后并没有给该指针赋一个有效的结构体对象地址,然后使用pShExeInfo访问结构体的cbSize成员的内存,因为pShExeInfo中的值为NULL,所以结构体cbSize成员的内存地址是结构体对象起始地址的偏移,因为结构体对象地址为NULL,cbSize成员位于结构体的首位,所以cbSize成员就是结构体对象的首地址,就是NULL,所以就访问64KB小地址内存块的异常,引发内存访问违例,导致程序发生崩溃闪退。
4、分析测试程序的崩溃
4.1、启动程序,将Windbg附加到目标进程上
下面我们就以上面讲到的测试程序为例,讲解一下使用Windbg动态调试的完整过程。测试程序如下:
在Button1按钮的响应函数中故意添加了一段会引发崩溃的代码,代码上面已经给出并进行讲解了。
启动程序后,打开Windbg,点击菜单栏File->Attach to a Process...,在进程列表中找到TestDlg.exe:
点击OK按钮即完成附加。
完成附加操作后,Windbg会自动中断下来,如下所示:
目标程序会因Windbg的中断被挂起,此时目标程序是没法操作的。此时需要在最下面的命令输入框中输入命令g,按下回车键,执行该命令,让Windbg跳过该中断,让目标程序恢复运行。这样目标程序就可以操作了。
4.2、使用Windbg初步分析崩溃
点击程序窗口的Botton1的响应函数,即去运行引发崩溃的代码,程序产生异常,Windbg会感知到异常并中断下来,如下所示:
从输出的信息中可以看到,程序发生了Acess violation内存访问违例的异常,并可以看到崩溃时的eax、ebx等各个寄存器中的值,并能看到发生崩溃的那条汇编指令。
程序最终是崩溃在某条汇编指令上,从汇编指令中我们可以看出是访问了0x0000000内存地址,在Windows系统中小于64KB的内存是禁止访问的。这块禁止访问的内存地址,是Windows系统故意预留的一块小地址内存区域,是为了方便程序员定位问题使用的。一旦访问到该内存区就会触发内存访问违例,系统就会强制将进程强制结束掉。
关于64KB禁止访问的小地址内存区域,在《Windows核心编程》一书中内存管理的章节,有专门的描述,相关截图如下所示:
4.3、找到相关模块的pdb文件,设置到Windbg中
仅仅通过查看崩溃时的各个寄存器的值以及发生崩溃的那条汇编指令是远远不够的,我们一般还需要查看崩溃时的函数调用堆栈。
于是我们在Windbg中输入kn命令查看崩溃时的函数调用堆栈,如下所示:
查看函数调用堆栈的命令,除了kn之外,还有kv和kp,使用kv可以查看到调用函数时的参数信息,如下:
从函数调用堆栈的最后一帧调用的函数来看,程序的崩溃是发生在TestDlg.exe文件模块中,不是其他的dll模块。显示的函数地址是相对TestDlg.exe文件模块起始地址的偏移,为啥看不到模块中具体函数名称呢?那是因为Windbg找不到TestDlg.exe对应的pdb文件,pdb文件中包含对应的二进制文件中的函数名称及变量等信息,Windbg加载到pdb文件才能显示完整的函数名。
如何才能找到TestDlg.exe文件对应的pdb文件?我们可以通过查看TestDlg.exe文件的时间戳找到文件的编译时间,通过编译时间找到文件对应的pdb文件。在Windbg中输入lm vm TestDlg*命令,可以查看到TestDlg.exe文件的详细信息,其中就包含文件的时间戳:(当前的lm命令中使用m通配符参数,所以在TestDlg后面加上了*号)
可以看到文件是2023年5月27日17点11分41秒生成的,就可以找到对应时间点的pdb文件了。
一般在公司正式的项目中,通过自动化软件编译系统,每天都会自动编译软件版本,并将软件的安装包及相关模块的pdb文件保存到文件服务器中,如下所示:
这样我们就可以根据模块的编译时间找到对应版本的pdb文件了。
我们找到了TestDlg.exe对应的pdb文件TestDlg.pdb,将其所在的路径设置到Windbg中。点击Windbg菜单栏中的File->Symbol File Path...,打开设置pdb文件路径的窗口,将pdb文件的路径设置进去,如下所示:
点击OK按钮之前,最好勾选上Reload选项,这样Windbg就会去自动加载pdb文件了。但有时勾选了该选项,好像不会自动去加载,我们就需要使用.reload /f TestDlg.exe命令去让Windbg强制去加载pdb文件(命令中必须是包含文件后缀的文件全名)。
关于pdb符号库文件的说明,可以查看我之前写的文章:
pdb符号库文件详解https://blog.csdn.net/chenlycly/article/details/125508858 设置完成后,我们可以再次运行lm vm TestDlg*命令去看看pdb文件有没有加载进来:
如果已经加载进来,则会在上图中的位置显示出已经加载进来的pdb文件的完整路径。,如上所示。
4.4、加载pdb后查看包含完整信息的函数调用堆栈
加载到TestDlg.exe文件对应的pdb文件之后,我们再次执行kn命令就可以包含具体的函数名及及代码的行号信息了,如下:
0:000> kn
# ChildEBP RetAddr
00 009eebf8 785ef632 TestDlg!CTestDlgDlg::OnBnClickedButton1+0x67 [c:\users\administrator\desktop\testdlg-空指针演示-2\crashdemo_testdlg\testdlg\testdlgdlg.cpp @ 489]
01 009eec3c 785efd7a mfc100ud+0x30f632
02 009eeca0 78649ac3 mfc100ud+0x30fd7a
03 009eecdc 78726c54 mfc100ud+0x369ac3
04 009eed40 783a977a mfc100ud+0x446c54
05 009eed54 78725859 mfc100ud+0xc977a
06 009eeec4 787257a2 mfc100ud+0x445859
07 009eeee4 78721cf3 mfc100ud+0x4457a2
08 009eef64 787222e6 mfc100ud+0x441cf3
09 009eef84 7850ad0b mfc100ud+0x4422e6
0a 009eefc0 77b8139b mfc100ud+0x22ad0b
WARNING: Stack unwind information not available. Following frames may be wrong.
0b 009eefec 77b7836a USER32!AddClipboardFormatListener+0x4b
0c 009ef02c 77dec81c USER32!GetClassLongW+0x7aa
0d 009ef0d0 77b77f6a ntdll!RtlDeactivateActivationContextUnsafeFast+0x9c
0e 009ef134 77b7bb2f USER32!GetClassLongW+0x3aa
0f 009ef170 77e14f5d USER32!CallNextHookEx+0x19f
10 009ef1a8 75ca107c ntdll!KiUserCallbackDispatcher+0x4d
11 009ef1ac 77b778cb win32u!NtUserMessageCall+0xc
12 009ef210 77b75d8f USER32!GetSystemMetricsForDpi+0x15cb
13 009ef230 691e6608 USER32!SendMessageW+0x6f
14 009ef250 691e65cd COMCTL32!CCEnableScrollBar+0x1028
15 009ef268 69225f33 COMCTL32!CCEnableScrollBar+0xfed
16 009ef304 77b8139b COMCTL32!SetWindowSubclass+0x3963
17 009ef330 77b7836a USER32!AddClipboardFormatListener+0x4b
18 009ef380 77b7b8e9 USER32!GetClassLongW+0x7aa
19 009ef414 77b760da USER32!Ordinal2712+0x1c9
1a 009ef488 77b7a2d8 USER32!DispatchMessageW+0x24a
1b 009ef4b8 7875def3 USER32!IsDialogMessageW+0x108
我们看到了具体的函数名CTestDlgDlg::OnBnClickedButton1,还看到了对应的代码行号489。通过这些信息,我们就能到源代码中找到对应的位置了,如下所示:
是访问了空指针产生的异常。当然上面的代码是我们故意这样写的,目的是为了构造一个异常来详细讲解如何使用Windbg进行动态调试跟踪的。
4.5、设置C++源代码的路径,Windbg会自动跳转到源代码对应的行号上
为了方便查看,我们可以直接在Windbg中设置C++源码路径,这样Windbg会自动跳转到源码对应的位置。点击Windbg菜单栏的File->Source File Path...,将源码路径设置进去:
然后Windbg会自动跳转到对应的函数及行号上:
然后点击函数调用堆栈中每行最前面的数字超链接,就可以自动切换到对应的函数中。上图中的函数调用堆栈中很多模块是系统库中的,比如mfc100u、User32等,这些库是系统库,是没有源码的。我们可以点击函数调用堆栈每行前面的序号,就会自动跳转到对应的代码中,如下:
4.6、有时需要查看函数中变量的值
有时我们在排查异常时,需要查看函数调用堆栈中某个函数中的变量值,去辅助排查。在某些场景下这种操作方式非常有用,我们在项目中多次使用过。可以查看函数中局部变量的值,也可以查看函数所在类对象的this指针指向的类对象中变量的值。我们要查看哪个函数,就点击函数调用堆栈中每一行前面的数字超链接,如下所示:
我们看到了局部变量pShExeInfo 的值:
我们可以点击this对象的超链接,就能查看当前函数对应的C++类对象中成员变量的值,如下:
4.7、使用.dump命令导出包含异常上下文的dump文件
比如问题出现在客户的电脑上,我们在使用Windbg初步分析后没找出引发崩溃的原因,我们不能长时间占用别人的电脑,我们可以使用.dump命令将包含异常上下文的信息导出到dump文件中,事后让客户将dump文件发给我们,我们在公司电脑做进一步分析排查。
使用.dump /ma D:\0604.dmp命令,将当前的异常信息保存到D:\0604.dmp文件中,命令执行效果如下:
会显示dump文件导出成功。
这里有两个概念的区别,一个是mini dump文件,一个是全dump文件。我们将windbg附加到进程上使用.dump命令导出的dump文件,是全dump文件,全dump文件中包含了所有的信息,可以查看到所有变量的信息。另外通过任务管理器导出的dump文件:
也是全dump文件。全dump文件因为包含了所有的信息,所以会比较大,会达到数百MB,甚至上GB的大小。但如果通过安装在程序的异常捕获模块CrashReport导出的dump文件就是非全dump文件,是mini dump文件,大概只有几MB左右,因为异常捕获模块捕获到异常后,会自动导出dump文件,保存到磁盘上,如果都导出体量很大的全dump文件,很大量消耗用户的磁盘空间,所以我们会设置生成mini dump文件。
在异常捕获模块中我们是通过调用系统API函数MiniDumpWriteDump导出dump文件的,我们通过设置不同的函数调用参数去控制生成mini dump文件的。
关于dump文件的分类与dump文件的生成方式,可以查看我之前写的文章:
dump文件类型与dump文件生成方法详解https://blog.csdn.net/chenlycly/article/details/127991002另外,Windbg等工具的下载链接如下:
链接:https://pan.baidu.com/s/1ID6_0RSYKbiy_tzfYDX3Ew
提取码:tn6i
4.8、可以在Windbg中进行断点调试
Windbg中有多个支持断点调试的命令,比如:
bl:用来显示当前设置的断点;
bp:设置断点;
bc:清除指定序号的断点。
断点调试是个很重要的功能,之前使用过Windbg的断点调试功能解决了多个问题,比如我之前写的一篇案例文章:
在Windbg中设置断点追踪打开C++程序远程调试开关的模块https://blog.csdn.net/chenlycly/article/details/130058430
5、最后
本文详细讲述了使用Windbg动态调试目标进程的一般步骤及完整过程,对于C++软件调试的初学者来说,很有参考价值,希望能给大家要提供一些借鉴或帮助。
相关文章:
使用Windbg动态调试目标进程的一般步骤详解
目录 1、概述 2、将Windbg附加到已经启动起来的目标进程上,或者用Windbg启动目标程序 2.1、将Windbg附加到已经启动起来的目标进程上 2.2、用Windbg启动目标程序 2.3、Windbg关联到目标进程上会中断下来,输入g命令将该中断跳过去 3、分析实例说明 …...
Linux驱动学习—输入子系统
1、什么是输入子系统? 输入子系统是Linux专门做的一套框架来处理输入事件的,像鼠标,键盘,触摸屏这些都是输入设备,但是这邪恶输入设备的类型又都不是一样的,所以为了统一这些输入设备驱动标准应运而生的。…...
计算机网络(2)
计算机网络(2) 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 计算机网络和因特网(2)分组交换网中的时延、丢包和吞吐量时延丢包吞吐量总结 协议层次及其服务模型模型类型OSI模型分析TCP/IP模型分析 追溯历史 小程一言 我…...
什么是预训练Pre-training—— AIGC必备知识点,您get了吗?
Look!👀我们的大模型商业化落地产品📖更多AI资讯请👉🏾关注Free三天集训营助教在线为您火热答疑👩🏼🏫 随着人工智能(AI)不断重塑我们的世界,其发展的一个关键方面已经…...
bat脚本sqlserver 不同数据库同步
如果你想使用批处理脚本(.bat)在 SQL Server 中同步不同数据库的数据,你可以考虑以下步骤: 设置环境变量: 确保你的系统环境变量中已经设置了 SQLCMD 和 BCP 的路径。 编写批处理脚本: 使用 sqlcmd 来执行…...
阶段十-分布式-Redis02
第一章 Redis 事务 1.1 节 数据库事务复习 数据库事务的四大特性 A:Atomic ,原子性,将所以SQL作为原子工作单元执行,要么全部执行,要么全部不执行;C:Consistent,一致性࿰…...
微信小程序实战-02翻页时钟-2
微信小程序实战系列 《微信小程序实战-01翻页时钟-1》 文章目录 微信小程序实战系列前言计时功能实现clock.wxmlclock.wxssclock.js 运行效果总结 前言 接着《微信小程序实战-01翻页时钟-1》,继续完成“6个页面的静态渲染和计时”功能。 计时功能实现 clock.wxm…...
每天刷两道题——第十一天
1.1滑动窗口最大值 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值 。 输入:nums [1,3,-1,-3,5,3,6,7], k 3 输出&…...
Git提交规范
一. 修改类型 每个类型值都表示了不同的含义,类型值必须是以下的其中一个: feat:提交新功能fix:修复了bugdocs:只修改了文档style:调整代码格式,未修改代码逻辑(比如修改空格、格式…...
apache2的虚拟主机的配置
APACHE2的虚拟主机配置 本章中心概括: 虚拟web主机的初步认识,在redhat系列系统中如何配置,在Debian系列系统中如何配置。 什么是apache2虚拟主机: 简单点讲,就是在同一个物理机中配置多个虚拟主机,从而达…...
Provide/Inject 依赖注入(未完待续)
父组件传递给子组件数据,通过props,但是需要逐层传递 provide/Inject 的推出就是为了解决这个问题,它提供了一种组件之间共享此类值的方式,不必通过组件树每层级显示地传递props 目的是为了共享那些被 认为对于一个组件树而言是全局的数据 p…...
力扣173. 二叉搜索树迭代器
深度优先搜索 思路: 遍历二叉搜索树,左子树总比根节点小,右子树总比根节点大;先深度遍历左子树,然后返回其父节点,然后遍历其右子树节点;使用栈数据结构存储节点数据,借用其“后进先…...
电脑找不到d3dcompiler43.dll怎么修复,教你5个可靠的方法
d3dcompiler43.dll是Windows操作系统中的一个重要动态链接库文件,主要负责Direct3D编译器的相关功能。如果“d3dcompiler43.dll丢失”通常会导致游戏无法正常运行或者程序崩溃。为了解决这个问题,我整理了以下五个解决方法,希望能帮助到遇到相…...
5.3 Android BCC环境搭建(eadb版 上)
写在前面 eadb即eBPF Android Debug Bridge,它是基于adeb的重构。后者曾随aosp 10发布在platform/external目录下。 一,root权限 这里再HighLight下,当前整个专栏都是基于开发环境来展开的,也就是Android设备需要具有root权限。因此该专栏下每一篇博客都是默认了当前开发…...
【算法题】44. 通配符匹配
题目 给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 ? 和 * 匹配规则的通配符匹配: ? 可以匹配任何单个字符。 * 可以匹配任意字符序列(包括空字符序列)。 判定匹配成功的充要条件是:字符模式必须能…...
vscode配置与注意事项
中文设置 https://zhuanlan.zhihu.com/p/263036716 应用搜索输入“Chinese (Simplified) Language Pack for Visual Studio Code”并敲回车键 底部信息窗没有的话 首先使用快捷键ctrlshiftp,Mac用户使shiftcommandp,然后输入settings.json 将下面的选…...
设计模式篇章(3)——七种结构型模式
结构型设计模式主要思考的是如何将对象进行合理的布局来组成一个更大的功能体或者结构体,这个现在讲有点抽象,用大白话讲就是利用现有的对象进行组合或者配合,使得组合后的这个系统更加好。好是相对于不使用设计模式,按照自己的堆…...
Window端口占用处理
您好,我是码农飞哥(wei158556),感谢您阅读本文,欢迎一键三连哦。 💪🏻 1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精…...
算法实战(二)
基础算法编程 题目来源([PAT题目](https://pintia.cn/problem-sets/14/exam/problems/type/6))7-2 然后是几点7-3 逆序的三位数7-6 混合类型数据格式化输入 题目来源(PAT题目) 7-2 然后是几点 有时候人们用四位数字表示一个时间,比如 1106 表示 11 点零 6 分。现在…...
网工内推 | 上市公司网工,NP认证优先,最高15薪+项目奖金
01 广东轩辕网络科技股份有限公司 招聘岗位:网络工程师 职责描述: 1、主要负责教育行业园区网的有线及无线网络项目的实施、维护、巡检等工作; 2、协助windows/linux平台服务器OS的安装、部署、配置与维护; 3、协助服务器、存储、…...
【LLM 论文阅读】NEFTU N E: LLM微调的免费午餐
指令微调的局限性 指令微调对于训练llm的能力至关重要,而模型的有用性在很大程度上取决于我们从小指令数据集中获得最大信息的能力。在本文中,我们提出在微调正向传递的过程中,在训练数据的嵌入向量中添加随机噪声,论文实验显示这…...
JS新手入门笔记整理:对象
对象可以分为两种:一种是“自定义对象”,另外一种是“内置对象”。自定义对象,指的是需要我们自己定义的对象。内置对象,指的是不需要我们自己定义的(即系统已经定义好的)、可以直接使用的对象。在JavaScri…...
Python GIL 一文全知道!
GIL 作为 Python 开发者心中永远的痛,在最近即将到来的更新中,终于要彻底解决了,整个 Python 社群都沸腾了 什么是GIL? GIL是英文学名global interpreter lock的缩写,中文翻译成全局解释器锁。GIL需要解决的是线程竞…...
数据库级别的MD5加密(扩展)
首先,我们要知道什么是MD5? 1.主要是增强算法的复杂性和不可逆性 2.MD5不可逆,具体的值MD5是一样的 3.MD5破解网站的原理,背后有一个字典 代码案例: -- 加密 update testMD5 set pwdmd5(pwd) where id1; update testMD5 set…...
Docker安装Jenkins,配置Maven和Java
前言 这是一个java的springboot项目,使用maven构建 安装准备 需要将maven和jdk安装在服务器上,Jenkins需要用到,还有创建一个jenkins的目录,安装命令如下: docker run -d -uroot -p 9095:8080 -p 50000:50000 --n…...
游戏分组(100用例)C卷 (JavaPythonC语言C++Node.js)
部门准备举办一场王者荣耀表演赛,有10名游戏爱好者参与,分为两队,每队5人。 每位参与者都有一个评分,代表着他的游戏水平。为了表演赛尽可能精彩,我们需要把10名参赛者分为实力尽量相近的两队。一队的实力可以表示为这一队5名队员的评分总和。 现在给你10名参与者的游戏水…...
python函数装饰器保存信息
1 python函数装饰器保存信息 python函数装饰器,可以通过实例属性、全局变量、非局部变量和函数属性,来保存被装饰函数的状态信息。 1.1 统计调用并跟踪 描述 通过装饰器统计函数调用次数,并且用打印来跟踪调用记录。 此装饰器用类的__ca…...
AI真正的Killer App 仍然缺席
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
Docker 镜像以及镜像分层
Docker 镜像以及镜像分层 1 什么是镜像2 Docker镜像加载原理2.1 UnionFs:联合文件系统2.2 Docker镜像加载原理2.3 Docker镜像的特点 3 镜像的分层结构4 可写的容器层 1 什么是镜像 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行…...
aigc 启动器 sd-webui-aki-v4 decode_base64_to_file
下载地址: SD-WebUI启动器 绘世-启动器 | 万物档案 decode_base64_to_file报错: File "E:\BaiduNetdiskDownload\stable diffusion\sd-webui-aki-v4\extensions\sd-webui-controlnet\scripts\external_code.py", line 7, in <module>fr…...
外贸网站做多少钱的/seo优化一般优化哪些方面
MQTT 协议快速入门课程简介:MQTT 协议实例全解析MQTT 协议的最佳实践和反模式MQTT 协议的安全性实践AIIoT 项目实战本课程深入浅出地介绍了 MQTT 协议的各种特性,对每个协议特性都辅以具体代码进行讲解,并通过一个 IoTAI 项目实战来具体展现 …...
云南网站建设哪家强/新品上市的营销方案
""" 1. os和sys都是干什么的? 2. 你工作中都用过哪些内置模块? 3. 有没有用过functools模块? """ #sys模块主要是用于提供对python解释器相关的操作 #os模块是Python标准库中的一个用于访问操作系统功能的模块…...
网站链接跳转怎么做/百度最容易收录的网站
后面对于内存方面的优化一直没有补充到上面的那篇文章里,等有空了,补上后续的一些内存优化手段,供交流分享。 3.Google近年来对Jetpack进行不断的补充和完善,我也对Jetpack进行一定的学习和引进,特别是lifecycle组件等…...
医院网站建设原理/关键词搜索查询
UNIX Shell 编程(6) 变量UNIX Shell允许把值存在变量中。要把值存入一个变量,只需写出变量名,后面紧跟一个等号,再紧跟变量值。variablevalue切忌中间含空格Shell中没有任何数据类型的概念,变量值通通认为是字符串。如:…...
太原哪里做网站好/百度网址
近年来,随着国内、国际局势日趋复杂,客户对防护型车辆的需求逐渐增多,而防护型车辆车身内外表面多为特种钢板。早期特种车体结构普遍为特种钢板焊接拼接结构,但是焊缝部位为防护薄弱环节,因此使用折弯一体化减少焊缝的…...
大连手机自适应网站制作公司/app联盟推广平台
当前的移动互联网时代,移动端应用的流量昂贵和敏感,为了统计APP内用户行为,或者需要收集某些产品数据,往往需要进行日志上报。日志上报往往又非常费流量,有没有一些好的节省流量的优化方法呢,这是本文将要讨…...