当前位置: 首页 > news >正文

基于WebRTC构建的程序因虚拟内存不足导致闪退问题的排查以及解决办法的探究

目录

1、WebRTC简介

2、问题现象描述

3、将Windbg附加到目标进程上分析

3.1、Windbg没有附加到主程序进程上,没有感知到异常或中断

3.2、Windbg感知到了中断,中断在DebugBreak函数调用上    

3.3、32位进程用户态虚拟地址和内核态虚拟地址的划分

4、用户态内存不足问题分析虚拟

4.1、判断是内存不足导致了malloc申请内存失败

4.2、为啥会中断在DebugBreak函数调用处呢?

5、占用程序进程的虚拟内存的因素有哪些?    

5.1、二进制文件

5.2、线程的栈空间

5.3、程序中申请的堆内存

6、当前用户态虚拟内存占用高的解决办法

6.1、修改WebRTC编译选项,减少内存占用

6.2、将程序做成64位的

6.3、使用Visual Studio的链接选项,将用户态虚拟内存从2GB扩充到3GB

6.4、使用多进程模式

7、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html       本文分享一下最近遇到的一个因虚拟内存不足导致程序发生闪退的问题排查案例,案例具有一定的代表性,希望能给大家提供一定的借鉴或参考。

1、WebRTC简介

       本案例中的软件是基于开源库WebRTC构建的,发生的软件问题也是与WebRTC有关的,所以先给大家简要地介绍一下WebRTC相关的内容。

       WebRTC(Web Real-Time Communication)是一个由Google发起的实时音视频通讯C++开源库,其提供了音视频采集、编码、网络传输,解码显示等一整套音视频解决方案,我们可以通过该开源库快速地构建出一个音视频通讯应用。

一个实时音视频应用软件一般都会包括这样几个环节:音视频采集、音视频编码(压缩)、前后处理(美颜、滤镜、回声消除、噪声抑制等)、网络传输、解码渲染(音视频播放)等。其中每一个细分环节,还有更细分的技术模块。

      虽然其名为WebRTC,但是实际上它不光支持Web之间的音视频通讯,还支持Windows、Android以及iOS等移动平台。WebRTC底层是用C/C++开发的,具有良好的跨平台性能。

       WebRTC因为其较好的音视频效果及良好的网络适应性,目前已被广泛的应用到视频会议、实时音视频直播等领域中。在视频会议领域,腾讯会议、华为WeLink、字节飞书、阿里钉钉、小鱼易连、厦门亿联等国产厂商均提供了基于WebRTC方案的视频会议。

       大家熟知的音视频专业服务商声网(Agora),更是基于开源WebRTC库,提供了社交直播、教育、游戏电竞、IoT、AR/VR、金融、保险、医疗、企业协作等多个行业的音视频互动解决方案。使用声网服务的企业包括小米、陌陌、斗鱼、哔哩哔哩、新东方、小红书、HTC VIVE 、The Meet Group、Bunch、Yalla等遍布全球的巨头、独角兽及创业企业。除了头部公司声网之外,也陆续有多家公司基于开源的WebRTC,开发出了多个音视频应用,提供了多个领域的音视频通信解决方案。

2、问题现象描述

       基于WebRTC的会议软件在加入会议后,会时不时发生闪退,虽然不是必现的,但已经有好几个用户反馈了,并且在某技术支持同事的电脑上也出现了频繁闪退的问题。程序闪退时,程序中安装的异常捕获模块没有感知到,所以没有生成dump文件。

虽然我们在程序中安装了异常捕获模块,但并不能捕获所有的软件异常或崩溃,只能捕获大部分的异常,所以程序发生异常时没有感知到,也实属正常。

3、将Windbg附加到目标进程上分析

       对于这类没有生成dump文件的场景,就需要使用Windbg进行动态调试了,即将Windbg附加到目标进程上,和目标进程一起跑。于是让这个技术支持同事每次运行软件时,都手动将Windbg附加到进程上,和进程一起跑,这样一旦程序发生异常,Windbg就会感知到,就会中断下来,这样就能看到出问题时的函数调用堆栈,就可以分析了。

3.1、Windbg没有附加到主程序进程上,没有感知到异常或中断

       但这位同事复现问题后,Windbg并没有中断下来,即Windbg没有感知到,按讲是不应该的,一旦程序发生异常,正在调试的Windbg会第一时间感知到并中断下来。后来发现,他是在Windbg中打开桌面快捷方式文件去启动软件的,而桌面快捷方式指向的是个引导启动的程序,不是主程序,该程序做一些初始校验的操作,校验通过后会自动将主程序启动起来。这样Windbg附加到的是引导程序的进程上,并没有附加到主程序进程上。

就像QQ的桌面快捷方式指向的是QQ安装目录下的QQScLauncher.exe:

该程序会做一些启动主程序QQ.exe前的一些检查,然后会将主程序QQ.exe启动起来。

在我们这个问题中,可以先将主程序启动起来,然后再将Widnbg附加到主程序进程上,就可以了。也可以通过Windbg将主程序启动起来,需要到安装目录中找到主程序的exe文件,打开该文件,不能通过桌面快捷方式去启动。

3.2、Windbg感知到了中断,中断在DebugBreak函数调用上    

       后来同事每次运行程序时都将Windbg附加到程序进程上,复现了问题,正在调试的Windbg中断了下来,发现中断在DebugBreak接口调用处,如下所示:

输入kn命令查看此时的函数调用堆栈: 

正是DebugBreak接口就是让正在调试的进程中断下来的。使用kn命令查看此时的函数调用堆栈,发现是WebRTC库中在调用malloc动态申请内存时返回了NULL,然后WebRTC库内部认为是异常情况,可能是认为内存申请不到后相关的业务都没法执行了,程序继续运行就没有意义了,于是直接调用abort接口将进程终止了。

       这就能说明为啥程序闪退时异常捕获模块没有感知到异常,因为malloc申请内存失败返回NULL,并没有产生C++异常,程序闪退是因为WebRTC内部调用abort接口强行将进程终止掉了。

       至于为啥会出现malloc申请内存失败的问题呢?估计是用户态的虚拟内存不够用了,我们的程序是32位的,系统会给程序进程分配4GB的虚拟内存,其中2GB是用户态的虚拟内存,我们的程序用户态的内存快到达上限了,没有空闲内存可用了,所以malloc申请内存失败了,返回了NULL。

      关于如何使用Windbg进行动态调试(使用Windbg进行动态调试的完整步骤),可以参见我之前写的文章:

使用Windbg动态调试目标进程的一般步骤及要点详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131029795

3.3、32位进程用户态虚拟地址和内核态虚拟地址的划分

       对于32为程序,是按32位进行内存寻址的,所以给32位程序进程分配了4GB的虚拟内存,程序中所使用的内存均是从这4GB的虚拟内存上划拨的,比如全局变量占用的内存、线程栈内存、程序申请的堆内存、二进制文件占用的代码段内存等。

       32位进程的这4GB虚拟内存,在Windows平台上,默认情况下,2GB是用户态虚拟内存,2GB是内核态虚拟内存;在Linux平台上,默认情况下,3GB是用户态虚拟内存,1GB是内核态虚拟内存。

       此外,用户态的代码只能访问用户态的内存地址,是禁止访问内核态内存地址的内核态的代码只能访问内核态的内存地址,是禁止访问用户态内存地址的关于32位进程和64位进程的虚拟内存地址划分,可以参见《Windows核心编程》一书中的截图:

       我们以前在排查软件异常崩溃时,经常遇到崩溃的那条汇编代码(位于用户态代码中)中访问了内核态的内存地址(可能是访问了未初始化的变量内存,也可能是访问了因内存越界被篡改的内存),用户态代码是禁止访问内核态内存地址的,强行访问会触发内存访问违例,引发程序崩溃。

      C++软件异常基本内存有关,关于引发C++程序内存错误的常见原因,可以参见我之前的文章:

引发C++程序内存错误的常见原因分析与总结icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/128599525

4、用户态内存不足问题分析虚拟

4.1、判断是内存不足导致了malloc申请内存失败

       复现问题时Windbg正好中断下来,软件进程暂停下来,正好此时使用Process Explorer查看我们软件进程的虚拟内存,确实已经用到1.8GB左右了,快接近2GB的上限了!其实离2GB的上限还有200MB的空余,但可能因为内存碎片的存在,都是一小块一小块分散的小内存块,而程序中要申请的是一段连续的内存块,找不到指定大小的连续内存块,就会出现内存分配失败了。

       如果在正在调试的Windbg中使用.dump命令手动导出dump文件,我们也可以事后通过dump文件的大小去初步估计出问题时进程占用的虚拟内存大小。在Windbg中导出的dump文件,属于全dump文件,将当时进程的内存信息都保存了下来,dump文件的大小接近当时进程的虚拟内存大小,可能会略小一点点。

       内存碎片的概念之前听说过,在这种场景下才感受到内存碎片的危害!有人说可以使用内存池,内存池可以减少内存碎片的出现,但实际上程序业务需要占用更多的内存,减少内存碎片也解决不了问题。

4.2、为啥会中断在DebugBreak函数调用处呢?

       复现问题时,为啥会中断在DebugBreak函数调用处呢?查看了函数调用堆栈中函数在WebRTC中的源码,malloc返回失败的代码如下所示:

1)申请内存的malloc返回NULL:

2)malloc返回NULL,会执行到RTC_CHECK宏中的rtc_FatalMessage接口: 

3)紧接着调用到FatalLog接口: 

4) FatalLog接口的实现如下:

我们在FatalLog接口的结尾处我们看到了DebugBreak系统API接口的调用,然后紧接着调用C函数abort。

       Windows API接口DebugBreak的作用就是让正在调试的调试器中断下来,目的是让调试器感知到当前的事件,所以Windbg中断在DebugBreak函数的调用处。此外,在调用DebugBreak接口后,会紧接着调用abort接口将当前进程终止掉,应该是WebRTC内部认为内存申请失败了,业务没法正常展开了,程序没法正常运行,没有继续存活下去的意义了,所以强行将程序进程终止了。

       调用C函数malloc申请内存申请失败时,malloc会返回NULL,不会抛出异常;如果使用new去申请,申请失败时默认会抛出bad_alloc异常,如果程序中没有处理这个异常,则会导致程序发生异常崩溃。当然,我们可以在new时使用nothrow,不让其抛出异常,返回NULL,示例代码如下:

#include <iostream>int main(){char *p = NULL;int i = 0;do{p = new(std::nothrow) char[10*1024*1024]; // 每次申请10MBi++;Sleep(5);}while(p);if(NULL == p){std::cout << "分配了 " << (i-1)*10 << " M内存"         //分配了 1890 Mn内存第 1891 次内存分配失败           << "第 " << i << " 次内存分配失败";}return 0;
}

       另外,abort的调用也会让正在调试的Windbg中断下来,我们来看看abort函数的内部实现:

/***
*void abort() - abort the current program by raising SIGABRT
*
*Purpose:
*   print out an abort message and raise the SIGABRT signal.  If the user
*   hasn't defined an abort handler routine, terminate the program
*   with exit status of 3 without cleaning up.
*
*   Multi-thread version does not raise SIGABRT -- this isn't supported
*   under multi-thread.
*******************************************************************************/
void __cdecl abort (void)
{_PHNDLR sigabrt_act = SIG_DFL;#ifdef _DEBUGif (__abort_behavior & _WRITE_ABORT_MSG){/* write the abort message */_NMSG_WRITE(_RT_ABORT);}
#endif  /* _DEBUG *//* Check if the user installed a handler for SIGABRT.* We need to read the user handler atomically in the case* another thread is aborting while we change the signal* handler.*/sigabrt_act = __get_sigabrt();if (sigabrt_act != SIG_DFL){raise(SIGABRT);}/* If there is no user handler for SIGABRT or if the user* handler returns, then exit from the program anyway*/if (__abort_behavior & _CALL_REPORTFAULT){_call_reportfault(_CRT_DEBUGGER_ABORT, STATUS_FATAL_APP_EXIT, EXCEPTION_NONCONTINUABLE);}/* If we don't want to call ReportFault, then we call _exit(3), which is the* same as invoking the default handler for SIGABRT*/_exit(3);
}

上述代码中先调用了raise(SIGABRT),该函数是触发一个SIGABRT信号终止异常,如果当前正在调试状态,会让调试器中断下来。接下来调用C函数_exit退出当前进程。 

       关于调用abort强制终止程序导致程序闪退的案例,还可以查看我之前的文章:

C++程序中执行abort等操作导致没有生成dump文件的问题案例分析icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/129003869

5、占用程序进程的虚拟内存的因素有哪些?    

      占用进程的虚拟内存空间的因素有很多,这里大概地罗列几个,大家可以简单地了解一下。我们可以从程序的五大内存分区的角度去看,程序的五大内存分区如下:

5.1、二进制文件

       主程序及主程序依赖的二进制库文件,都需要加载到进程空间中,都占用一定的虚拟内存。exe主程序依赖底层的多个业务库和系统dll库,比如业务库有组件dll库、协议dll库、网络dll库、开源库等,可能会依赖上百个dll库。这些dll库在主程序启动时,会加载到程序进程的进程空间中,会占用进程的虚拟内存空间,属于代码段的虚拟内存。

       如果能减少dll库的依赖,减小依赖的dll库文件的大小,可以减少程序对虚拟内存的占用。特别对于一些大型的开源库,一方面要减少程序安装包的大小,另一方面减少二进制文件对虚拟内存的占用,需要进行一些裁剪,开源库中也提供了一些宏开关和编译选项。比如google开源的嵌入式浏览器框架库libcef,默认是比较大的,编译后的dll库要占到好几十MB,可以对该库进行裁剪。有时为了进行深度的裁剪和优化,甚至会去直接修改开源代码。

5.2、线程的栈空间

       程序中创建了多个线程(多个模块都创建了线程),每个线程都要分配对应的栈空间,线程越多占用的栈空间越多,这是栈空间也是从进程的虚拟内存上划拨的。但对于应用程序,开多个线程去并行处理任务,也是必不可少的。

对于线程占用的栈空间大小,Windows下每个线程默认的栈空间大小是1MB,Linux下每个线程的默认的栈空间是8MB。

5.3、程序中申请的堆内存

        C++程序中使用的大部分内存都是堆内存,堆内存占总虚拟内存的大部分。堆内存是通过使用new或者调用malloc等函数申请的。

在Windows平台上,动态申请内存的方式有多种,比如使用new(要用delete去释放),比如使用malloc(要用free去释放),再比如调用系统API函数HeapCreate或者HeapAlloc(要用HeapFree去释放),还有可以调用API函数VirtualAlloc(要用VirtualFree去释放),还有其他的API函数。

       要尽量节约内存,按需分配,使用的buffer大小可能会动态变化,频繁动态地去申请和释放内存,可能会产生很多内存碎片。这也是上来就申请固定长度的buffer的好处,可以减小生成内存碎片。使用内存池可以减少内存碎片,但对于本问题,确实需要使用很多虚拟内存,使用内存池减少内存碎片作用也不是很大。

6、当前用户态虚拟内存占用高的解决办法

       WebRTC开源库比较大,会消耗很多的内存,如何解决WebRTC占用大量虚拟内存的问题,有如下的方法。

6.1、修改WebRTC编译选项,减少内存占用

       可以尝试修改WebRTC编译选项,对其进行裁剪缩编,释放出一些占用内存的代码,但这种做法降低内存的效果有限,因为WebRTC作为大型库本来就需要占用大量的内存资源。

6.2、将程序做成64位的

       可以将主程序做成64位的,64位程序的用户态虚拟内存非常大,可以“肆无忌惮”的使用。但占用的虚拟内存过大,在代码执行过程中虚拟内存要切换到物理内存上,会来回频繁地切换,也会影响程序的执行效率。此外,物理内存较小,也会影响虚拟内存到物理内存的切换,也会显著降低程序的运行速度。

6.2.1、我们的程序为了兼容32位系统,需要做成32位的

       我们的程序之所以还是32位的,是因为我们需要兼容32位系统。有些人说,为啥不直接将主程序做成x64(64位程序)的呢?因为我们的程序还要兼容32位的系统,虽然现在普遍使用的Win10和Win11都是64位的,但还有少部分客户在使用32位的Win7系统,什么样的客户都有,不排除有使用32位系统的可能。

64位程序是没法在32位系统上运行的,但32位程序可以在64位系统上运行,这是操作系统去做兼容的。

6.2.2、关于32位程序和64位程序的说明

       32位exe或dll是不能和64位exe或exe文件混用的,系统是严格区分二进制文件位数的,32位exe或dll文件只能使用(依赖)32位exe或dll文件,64位exe或dll文件只能使用(依赖)64位的exe或dll文件。比如32位的exe主程序如果使用64位dll库,则启动时会报错。

       对于Windows系统库,64位系统的系统库都有两个版本的,分别是32位系统库和64位系统库。32位的系统库则存放在C:\Windows\SysWOW64目录中(注意WOW64不是64位系统库目录,WOW64是32位程序运行在64位系统上的意思);64位系统库存放在C:\Windows\System32目录中:

       所以,32位程序依赖的32位系统库都在C:\Windows\SysWOW64目录中。这个SysWOW64和system32目录很容易混淆,前几天还有个同事问我这两个目录对应关系到底是啥,他之前一度以为system32目录下的是32位系统库,SysWOW64目录下的是64位系统库,事实却正好相反。

       当32位程序在64位Windows上运行时,会有个重定向问题,可以查看我之前的文章:

关于32位程序在64位系统下运行中需要注意的重定向问题(有图有真相)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/53119127Win7用户帐户控制数据重定向icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/53408212

6.3、使用Visual Studio的链接选项,将用户态虚拟内存从2GB扩充到3GB

       可以在Visual Studio链接选项中打开扩大用户态虚拟内存的选项/L largeAddressAware,如下所示:

这样可以将用户态虚拟内存扩到3GB,这样可以有效缓解内存不够用的问题。

       32进程只有4GB的虚拟内存,如果将用户态虚拟内存由2GB扩到3GB,内核态的虚拟内存应该会被压缩到1GB,这样会不会导致内核态的代码执行比较慢,导致程序的运行性能下降呢?可能运行性能会有一定的损失,但既然系统运行这种扩充用户态虚拟内存的方式,应该影响不会很大。

6.4、使用多进程模式

       但上述方法,在使用WebRTC开源库时可能有问题,如果要解更多路数的视频,会占用更多的内存。可以考虑将WebRTC封装成进程,使用多进程的模式,主进程与WebRTC进程使用RPC方式进行接口的调用。像Chrome那样,搞多个进程,不同的进程处理不同的事务,一个进程崩溃了,不会影响到主进程,将崩溃的进程重新启动。但是多个进程之间需要通信,需要协同控制,控制不好也容易出问题。进程之间如何高效地的传递数据也是个问题,这都需要人力和技术去支撑。但多进程模式将是最终且最稳妥的解决方案。

7、最后

       针对我们遇到的上述问题,目前的做法是,一边优化内存占用,一边使用扩大用户态虚拟内存的做法,同步进行。

相关文章:

基于WebRTC构建的程序因虚拟内存不足导致闪退问题的排查以及解决办法的探究

目录 1、WebRTC简介 2、问题现象描述 3、将Windbg附加到目标进程上分析 3.1、Windbg没有附加到主程序进程上&#xff0c;没有感知到异常或中断 3.2、Windbg感知到了中断&#xff0c;中断在DebugBreak函数调用上 3.3、32位进程用户态虚拟地址和内核态虚拟地址的划分 …...

通过jdk自制https证书并配置到nginx并配置http2

生成证书 这里使用自己生成的免费证书。在${JAVA_HOME}/bin 下可以看到keytool.exe,在改目录打开cmd然后输入&#xff1a; keytool -genkey -v -alias lgq.com -keyalg RSA -keystore d:/zj/ssl/fastfly.com.keystore -validity 3650生成证书过程中&#xff1a;【你的名字】对…...

祝贺中国煤科重庆研究院和达索、百世慧PLM项目顺利结项

引言 2023年10月17日&#xff0c;中国煤科重庆研究院与达索系统、百世慧在重庆研究院会议室召开了产品全生命周期管理&#xff08;PLM&#xff09;系统结项会。中国煤科重庆研究院科技发展部副主任孙海涛、测控技术研究分院副院长于庆、重庆大学教授鄢萍、达索公司工业装备部南…...

基于springboot实现数码论坛系统设计与实现系统【项目源码+论文说明】

基于springboot实现数码论坛系统设计与实现系统演示 摘要 网络的广泛应用给生活带来了十分的便利。所以把数码论坛与现在网络相结合&#xff0c;利用java技术建设数码论坛系统&#xff0c;实现数码论坛的信息化。则对于进一步提高数码论坛发展&#xff0c;丰富数码论坛经验能起…...

魔域开服需要什么样的配置

魔域是一个非常受玩家喜欢的游戏&#xff0c;是一款大型魔幻题材的网络游戏&#xff0c;关于魔族入侵亚特大陆的故事&#xff0c;玩家在游戏里扮演不同的角色捍卫大陆安全&#xff0c;很多玩家想要更多的体验就会选择开新服&#xff0c;今天就让小编来讲一讲魔域开服要什么配置…...

7个好用的PC端设计软件,设计必看!优漫动游

身为设计师的你是不是还在为到处寻找合适的设计软件而烦恼&#xff1f;是不是在为因为没能用上好的软件而影响自己设计生涯的事情感到焦虑&#xff1f;别担心&#xff0c;你的烦恼可能每个成熟的设计师都遇到过&#xff0c;但他们最终都走了过来。借助以下7个好用的PC端设计软件…...

10-动画animation

动画animation 动画-过渡和动画之间的异同-animation-name 指定要绑定到选择器的关键帧的名称&#xff0c;告诉系统需要执行哪个动画-animation-duration 动画指定需要多少秒或毫秒完成&#xff0c;告诉系统动画持续的时长-animation-timing-function 设置动画将如何完成一个周…...

【带头学C++】----- 1.基础知识 ---- 1.24 逻辑控制语句

1.24 逻辑控制语句 本节主要学习关于C逻辑控制的一些语句的用法&#xff0c;结合实践代码总结一下。 1.24.1 if以及if - else&#xff08;条件语句&#xff09; 1.if语句&#xff1a; if(条件){执行语句; }//一旦执行if语句&#xff0c;先判断()里的条件是否满足&#xff0c…...

微信公众号分销商城源码系统+多元商家+收银台 带完整的搭建教程

给大家推荐一款微信公众号分销商城源码系统&#xff0c;这是一个全新三级分销商城&#xff0c;功能十分丰富。一起来看看你吧。 微信公众号分销商城的功能&#xff1a; 1.商品展示和推广&#xff1a;商家可以在商城中展示商品信息&#xff0c;包括商品名称、价格、库存等&#…...

排序算法:选择排序,分别用c++、java、python实现

选择排序介绍 选择排序&#xff08;Selection Sort&#xff09;是一种简单的比较排序算法&#xff0c;它的工作原理如下&#xff1a; 分区: 将待排序的数组分成两个部分&#xff0c;一个部分是已排序的子数组&#xff0c;另一个部分是未排序的子数组。初始时&#xff0c;已排序…...

支付宝支付接入流程

一、 接入准备 支付宝支付流程没有微信那么复杂&#xff0c;而且支付宝支持沙箱。登录支付宝开放平台控制台 点击开发工具中的沙箱 接口加密方式&#xff0c;我这里使用的是自定义密钥。生成密钥的方式 使用支付宝官方提供的密钥工具&#xff0c;唯一要注意的是支付宝密钥工具…...

管理员|顾问必看!8个Salesforce权限集的最佳实践

Salesforce中的权限一直始终是热门话题。权限集是简档的附加。它们通常具有相同的设置&#xff0c;用于增加用户的权限&#xff0c;使其超过简档提供的权限。可以将简档视为许多用户共有的基本权限集&#xff0c;而权限集是部分用户需要的额外权限。 本篇文章将介绍Salesforce…...

【linux进程(六)】环境变量再理解程序地址空间初认识

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; 程序地址空间 1. 前言2. 在ba…...

10步开启SAFe敏捷发布列车

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 敏捷畅想一、培训 SAFe 项目顾问 (SPC)二、培训精益敏捷领导者三、 举办价值流研讨会并确定您的第一个敏捷发布系列四、 定义/设置 ART 和团队五、 担任重要角色六、…...

面试题之Vue和React的区别是什么?

一提到前端框架&#xff0c;相信大家都对Vue和React不陌生&#xff0c;这两个前端框架都是比较主流的&#xff0c;用户也都比较多&#xff0c;但是我们在使用这些框架的时候&#xff0c;是否对这两个框架之间的区别有所了解呢&#xff1f;接下来&#xff0c;让我们来一起的系统…...

Linux基础知识——概述和常用文件管理命令

Linux基础知识——概述和常用文件管理命令 文章目录 Linux基础知识——概述和常用文件管理命令概述常用的一些文件指令 概述 终端&#xff1a;一个terminal窗口就是以个屏幕, 远程连接了一个服务器, 每一个terminal可以连接到任何一个其他服务器上;关掉terminal相当于只是关掉…...

腾讯云创建了jenkins容器,但无法访问

1、首先&#xff0c;查看本机能不能ping通你的腾讯云服务器 如果ping的通那就下一步 2、查看腾讯云服务器的防火墙关了没&#xff0c;没关关掉、 firewall-cmd --state not running 3、那就在云服务器的控制台开放端口...

C语言的const函数修饰指针

文章目录 一、const函数的作用 int a 10; int *p ; p &a;从上面的代码分析&#xff0c;p 存放的就是a的地址&#xff0c; *p 存放的就是 a 的值。 一、const函数的作用 一旦使用了const函数修饰一个变量&#xff0c;那么这个变量就无法变化了。 所以下面三种情况&#…...

EasyExcel使用方式(包含导出图片)

1、导EasyExcel依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version> </dependency> 2、创建导出excel的实体类 Getter Setter EqualsAndHashCode HeadStyle(fillF…...

redis学习(三)——java整合redis

Jedis Jedis可以用于java连接redis数据库 新建一个maven项目&#xff0c;导入Jedis依赖 <dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test…...

OpenText 安全取证软件——降低成本和风险的同时,简化电子取证流程

OpenText 安全取证软件&#xff0c;行业标准的数字调查解决方案&#xff0c;适用于各种规模和各种行业的组织 降低成本和复杂性 • 远程调查比轮流调查过程更有效 对结果持有信心 • 磁盘级可见性可以完成相关端点数据的搜索和收集 谨慎调查 • 完整的网络调查&#xf…...

【vue】vue前端、生产(线上)环境请求unicloud云服务空间axios报错

目录 原因总结&#xff1a;借助Nginx使得axios可跨域请求 原因 使用axios的时候&#xff0c;如果是开发环境下&#xff0c;WebStorm&#xff08;IDEA&#xff09;会自带跨域功能&#xff0c;说白了就是不用考虑跨域的事情了。但是在生产环境下&#xff0c;vue前端编译成静态文…...

JVM详解(InsCode AI 创作助手)

JVM是一个虚拟的计算机&#xff0c;它有自己的硬件架构&#xff0c;如处理器、堆栈和寄存器等&#xff0c;也有自己的指令系统。JVM的主要任务是负责加载、验证、编译和执行Java程序。 一、JVM参数默认配置如下 内存设置&#xff1a; 初始堆内存大小&#xff1a;物理内存的1/…...

华为c语言编程规范

提示&#xff1a;附件为编程规范 文章目录 前言一、华为c语言编程规范总结 前言 例如&#xff1a;华为规范下载 一、华为c语言编程规范 该处使用的url网络请求的数据。 总结 提示&#xff1a;这里对文章进行总结&#xff1a; 例如&#xff1a;以上就是今天要讲的内容&#xf…...

SQL Server Management Studio (SSMS)的安装教程

文章目录 SQL Server Management Studio (SSMS)的安装教程从Microsoft官网下载SQL Server Management Studio安装程序。选中安装程序右键并选择“以管理员的身份运行”选项选择安装目录&#xff0c;单击“安装”按钮开始安装过程安装成功界面安装完成后&#xff0c;您可以启动S…...

React 图片瀑布流

思路&#xff1a; 根据浏览器宽度&#xff0c;确定列数&#xff0c;请求的图片列表数据是列数的10倍&#xff0c;按列数取数据渲染 Index.js: import React from react import { connect } from react-redux import { withRouter } from react-router-dom import { SinglePag…...

C++数据结构X篇_21_插入排序(稳定的排序)

文章目录 1. 插入排序原理2. 算法图解3. 核心代码&#xff1a;4. 插入排序整体代码实现 1. 插入排序原理 插入排序是一种最简单直观的排序算法&#xff0c;它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相…...

【Unity】3D跑酷游戏

展示 finish_all * 方块跑酷 1.教程链接 翻墙&#xff1a;https://www.youtube.com/watch?v9ZEu_I-ido4&listPLPV2KyIb3jR53Jce9hP7G5xC4O9AgnOuL&index3 2.基础制作 最终成果 2.1 基本场景 1.创建Cube作为跑道 1&#xff09;记得把位置Reset&#xff1b; 2&#…...

bp前端验证码绕过及token绕过

前端验证码绕过及token绕过 原文参考&#xff1a;xiu 文章目录 前端验证码绕过及token绕过原文参考&#xff1a;[xiu](http://www.xiusafe.com/2023/10/25/%E9%AA%8C%E8%AF%81%E7%A0%81%E7%BB%95%E8%BF%87/)1 验证码爆破1. 登录Pikachu&#xff0c;先获取登录的api接口2 验证码…...

Jmeter(十四):跨线程组传递jmeter变量及cookie的处理详解

setUp线程组 setUp thread group 一种特殊类型的线程组&#xff0c;用于在执行常规线程组之前执行一些必要的操作。 在 setup线程组下提到的线程行为与普通线程组完全相同。不同的是执行顺序--- 它会在普通线程组执行之前被触发&#xff1b; 应用场景举例&#xff1a; A、测…...