如何配置X86应用程序启用大地址模式(将用户态虚拟内存从2GB扩充到3GB),以解决用户态虚拟内存不够用问题?(项目实战案例解析)

news2024/11/16 16:01:31

目录

1、概述

2、为什么不直接将程序做成64位的?

3、进程内存不足导致程序发生闪退的案例分析

3.1、问题说明

3.2、将Windbg附加到程序进程上进行动态调试

3.3、动态调试的Windbg感知到了中断,中断在DebugBreak函数调用上

3.4、malloc或new失败的可能原因分析

3.5、为什么没能生成dump文件?

3.6、本例中malloc返回NULL的原因分析

3.7、为啥有的机器不出现,只在个别电脑上出现?

4、程序用户态虚拟内存占用高导致不够用的解决办法

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

4.2、将程序做成64位的

4.3、使用多进程模式

4.4、使用Visual Studio的链接选项,将用户态虚拟内存从2GB扩充到3GB(最终选择的这个方法)

5、最后


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html       对于32位程序,默认情况下其用户态虚拟内存只有2GB,可能会出现内存不够用的情况,继而出现后续内存申请失败,导致软件出现异常。本文结合项目中出现的一个具体问题实例,详细讲述问题的排查定位的过程,并详细讨论了解决用户态虚拟内存不够用的手段与策略,最后讲述如何配置X86应用程序启用大地址模式(将用户态虚拟内存从2GB扩充到3GB)去解决内存不够用的问题。

1、概述

        对于32位程序,系统给程序进程分配4GB的虚拟内存,默认情况下,用户态虚拟内存占2GB,内核态虚拟内存占2GB。对于应用程序,业务代码基本都是运行在用户态中的,占用的是用户态的虚拟内存。可能会因为程序模块多占用的内存过大,也可能是程序中存在内存泄漏,导致程序进程占用的用户态虚拟内存达到或者接近2GB的上限,导致后续内存申请失败,或者产生Out of memory内存耗尽的异常。

        如果是内存泄漏导致的,则要排查泄漏的原因,解决泄漏问题。

        如果是程序业务模块过多,占用了大量的内存,使程序占用的用户态虚拟内存接近2GB(快达到2GB的上限),导致后续内存申请失败,则需要对程序占用的内存进行优化,减少程序对虚拟内存的占用。如果内存优化空间有限,仍然无法解决问题,则可以将程序的用户态虚拟内存从2GB扩充到3GB,将问题规避掉。

对于32程序,总的虚拟内存是4GB,默认情况下,用户态虚拟内存占2GB,内核态虚拟内存占2GB。如果将用户态虚拟内存由2GB扩充到3GB,则内核态虚拟内存会从2GB较少到1GB,即内核态虚拟内存就变小了,对运行在内核态的模块的执行效率会带来一定的影响,虽然这种影响不大。另外,尽量对虚拟内存进行优化,如果程序占用的虚拟内存较大,要频繁地在虚拟内存与物理内存之间切换,也会对程序的执行效率产生影响。

2、为什么不直接将程序做成64位的?

       64位程序的虚拟内存到大的多,既然32位程序的虚拟内存有限,为什么不做成64位的呢?32位程序可以在32位操作系统中运行,也可以在64位操作系统中运行(64位系统兼容32位程序)。但64位程序只能在64系统中运行,无法在32位系统运行。

        为了同时支持32位和64位操作系统,将程序都做成32位的,当然,有些软件做成了32位和64位两个版本,可以根据操作系统的位数,选择安装对应位数的程序。

       如果要将程序做成64位的,则程序从上到下的所有模块都要编译成64位的,因为32位模块和64位模块是不同混在一起使用的,如果强行混在一起使用,程序会报错的。

       以64位Windows系统为例,64位系统是如何保证32位程序与64位都能正常运行的呢?程序会依赖很多系统dll库,而32位程序只能依赖使用32位的dll库,64位程序也只能依赖使用64位的dll库。系统为了同时支持32位与64位程序的运行,提供了32位版本和64位版本的系统dll库:

1)C:\Windows\System32:64位系统dll库目录。

2)C:\Windows\SysWOW64:32位系统dll库目录。

系统在启动程序时会根据程序的位数,去选择加载对应位数的系统dll库。

       方便大家理解和记忆,此处说一下C:\Windows\SysWOW64路径中的WOW64的含义,MSDN上对WOW64的解释如下:

WOW64 is the x86 emulator that allows Win32-based applications to run on 64-bit Windows. It is intended to run 32-bit personal productivity applications needed by software developers and administrators. It is not intended to run 32-bit server applications. 

WOW64的大致含义是,W-Win32,O-On,W64-Win64(64-bit Windows),32位程序运行在64系统上。

3、进程内存不足导致程序发生闪退的案例分析

3.1、问题说明

       之前有客户反馈,我们的客户端软件在他们某台华为MATE笔记本电脑上运行时,会时不时地出现闪退问题(问题不是必现的)。程序闪退时并没有弹出崩溃的提示框(如果程序的异常捕获模块感知到程序发生了崩溃,会弹出一个崩溃提示框),说明程序中安装的异常捕获模块并没有感知到异常,所以没有生成dump文件,所以也就没法使用Windbg静态分析dump文件的方式去分析这个问题。

程序中安装的异常捕获模块,大概只能捕获到90%左右场景的异常,有少部分异常是捕捉不到的。对于异常捕获不到的场景,则需要使用其他方法排查分析,比如使用Windbg进行动态调试。

3.2、将Windbg附加到程序进程上进行动态调试

       既然异常捕获模块没有感知到,我们只能将Windbg附加到程序进程上进行动态调试,即将Windbg附加到程序进程上,和程序一起跑,如果程序发生异常,Windbg会第一时间感知到并中断下来,这个时候我们就趁这个中断的机会,去查看函数调用堆栈去分析。

       但这个问题不是必现的,只能让客户每次启动程序时,都手动将Windbg附加到目标进程上,让Windbg跟着程序一起跑。一旦问题复现,Windbg就会感知到并中断下来。


        在这里,给大家重点推荐一下我的几个热门畅销专栏(博客主页还有其他专栏,可以去查看)

专栏1:(该精品技术专栏的订阅量已达到430多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!)

C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2: 

C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战经验为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对C++相关知识点进行详细地展开与剖析!专栏涉及了C/C++开发领域多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

VC++常用功能开发汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585

专栏将10多年C++开发实践中常用的功能,以高质量的代码展现出来,并对相关功能的实现细节进行了详细的说明。这些常用的代码,其质量与稳定性是有保证的,可以直接拿过去使用,可以有效地解决C++软件开发过程中遇到的问题。


3.3、动态调试的Windbg感知到了中断,中断在DebugBreak函数调用上

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

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

正是DebugBreak接口就是让正在调试的进程中断下来的。DebugBreak是Windows API函数,从函数名称上也能看出来,该函数就是让正在调试的调试器中断下来,此时的中断确实是调用了DebugBreak引起的中断。

       于是顺着函数调用堆栈向上看,问题是出在WebRTC开源库中的,然后根据函数调用堆栈中的函数,找到对应的C++源码,看到是代码中调用malloc申请动态内存时,申请内存失败,返回空指针NULL,然后引发DebugBreak的调用,具体流程可以对照下列代码看:

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

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

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

4) FatalLog接口中调用了DebugBreak接口

       此外,我们在实际调试时发现,使用g命令将DebugBreak函数调用引发的中断跳过去,Windbg还会产生一次中断,是因为调用abort系统函数,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 _DEBUG
    if (__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);
}

       abort函数内部是通过调用exit系统函数将当前进程强制退出的,但在退出之前会调用raise(SIGABRT),该函数触发一个SIGABRT信号终止异常,如果当前正在调试状态,会让调试器中断下来。

3.4、malloc或new失败的可能原因分析

       如果malloc申请内存失败,则会返回NULL;如果new申请内存失败,默认会抛出bad_alloc异常。  那为啥会出现malloc或new操作失败的问题呢?之前我们总结过,一般malloc或new失败可能是以下几种原因导致的:

1)申请的内存过大,进程中没有这么大内存可用了
可能受一些异常数据的影响,申请了很大尺寸的内存。比如前段时间排查一个崩溃问题,当时因为数据有异常,一次性申请了9999*9999*4*2 = 762MB的堆内存,进程中没有这么大可用的堆内存了,所以申请失败了。
2)用户态的内存已经达到了上限,申请不到内存了       
有可能是虚拟内存占用太多,也有可能代码中有内存泄露,导致用户态的虚拟内存被消耗完了。对于一个32程序,一个进程分配了4GB的虚拟地址空间,而用户态和内核态内存各占一半,即用户态的虚拟内存只有2GB,如果程序占用的虚拟内存比较大,比如接近2GB的用户虚拟内存了,再申请大的内存就会申请失败了。或者程序中有内存泄露,快要把用户态的2GB的虚拟内存给占用完了,再申请内存可能会申请失败的。
3)进程中的内存碎片过多    
如果进程中在大量的new和delete,产生了大量的小块内存碎片,可用的内存被切割成一小块一小块的小内存块,如果要申请一块长度很长的内存,因为到处是内存碎片,没有这么一大块连续的可用内存,可能会导致内存申请失败的。
4)发生堆内存越界
堆内存被破坏,导致new操作产生异常(此时new不会返回NULL,会抛出异常)。我们可以在出问题的地方,对该处的new添加一个保护(但不可能对代码中所有new的地方都加这样的保护),我们通过添加try...catch去捕获new抛出的异常,并将异常码打印出来,如下所示:(下面的代码在循环申请内存,直到内存申请失败为止,主要用来测试用)

​#include <iostream>
using namespace std;
 
int main(){
    char *p;
    int i = 0;
    try
    {
        do{
            p = new char[10*1024*1024];
            i++;
            
            Sleep(5);
        }
        while(p);
    }
    catch(const std::exception& e)
    {
        std::cout << e.what() << "\n"
                    << "分配了" << i*10 << "M" << std::endl;
 
    }
    
    return 0;   
}

3.5、为什么没能生成dump文件?

       现在我们再回过头去看看,程序发生闪退时为什么没有生成dump文件。 上面已经分析出程序闪退的原因了,是因为WebRTC开源库中调用malloc申请内存失败(因为进程的用户态虚拟内部不够用了,没有足够空闲的内存可供分配了)返回空指针NULL,WebRTC认为申请内存失败了,业务没法正常跑下去了,认为是致命的,然后最终调用abort系统函数强行将当前进程终止的。

       程序中只是调用malloc申请内存失败,然后调用abort强行终止进程,并没有产生C++异常或崩溃。并没有产生C++异常或崩溃,异常捕获模块是感知不到的,所以没生成dump文件的,这和运行时实际表现出来的现象是完全吻合的!

       如果代码中不是调用malloc去动态申请内存,而是使用new去申请,则在申请不到内存时new内部会抛出bad_alloc异常,这个会导致程序崩溃的,异常捕获模块应该能感知到,会生成dump文件。

3.6、本例中malloc返回NULL的原因分析

       在本例中排除了内存泄漏的可能,推测是程序占用的虚拟内存过多,接近程序用户态虚拟内存2GB的上限,导致后续申请内存时没有足够的内存可供分配了,所以申请内存失败!

       我们软件之前的版本,没有使用WebRTC开源库,一直没有这个问题的。这个问题是在引入WebRTC开源库后才出现的,可能和引入的WebRTC有关系的。WebRTC开源库内部功能庞大,内部包含了大量的业务和逻辑,会占用大量的内存,按讲是不适合用在32位程序中,因为32位程序的用户态虚拟内存默认只有2GB,很有可能会出现用户态虚拟内存不够用的情况。

3.7、为啥有的机器不出现,只在个别电脑上出现?

       为啥这个问题有的机器不出现,只在个别电脑上出现呢?可能和机器的硬件配置及操作系统版本有关系。不同版本的操作系统的内存管理机制可能是有差异的。WebRTC开源库内部会根据机器的配置及网络带宽,去动态地调整音视频编码的分辨率等参数,会消耗不同大小的内存。

4、程序用户态虚拟内存占用高导致不够用的解决办法

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

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

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

WebRTC库的源码就有10多个GB,是个非常庞大的开源库,内部包含了大量的业务逻辑和功能,需要占用大量的内存!有些内存在库初始化的时候就申请了,即很多内存一上来就占用上了,而不是需要使用时再去申请。

4.2、将程序做成64位的

       要将程序做成64位的,底层的模块都要编译成64位的,32位模块与64位模块是不同混在一起使用的。如果强行混在一起,则运行会报错的。程序底层包含了上百个模块,都要将代码移植到64位上,可能会遇到这样那样的问题,短时间内完成迁移,会产生很多bug的。

        再就是我们的程序要兼容32位操作系统,目前只能做成32位的,没有人力去分别制作32位版本和64位版本。

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

4.3、使用多进程模式

        但上述方法,在使用WebRTC开源库时可能有问题,如果要解码更多路数的视频,会占用更多的内存。可以考虑将WebRTC封装成进程,使用多进程的模式,主进程与WebRTC进程使用RPC方式进行接口的调用。像Chrome那样,搞多个进程,不同的进程处理不同的事务,可以将程序占用的内存分摊到不同的进程上。并且一个进程崩溃了,也不会影响到主进程,将崩溃的进程重新启动起来就好。

       但多个进程之间需要通信,需要协同控制,控制不好也容易出问题。进程之间如何高效地的传递数据也是个问题,这都需要人力和技术去支撑。但多进程模式是比较稳妥的解决方案之一。

4.4、使用Visual Studio的链接选项,将用户态虚拟内存从2GB扩充到3GB(最终选择这个方法)

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

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

       32位进程只有4GB的虚拟内存,如果将用户态虚拟内存由2GB扩到3GB,内核态的虚拟内存应该会被压缩到1GB,这样会不会导致内核态的代码执行比较慢,导致程序的运行性能下降呢?可能运行性能会有一定的损失,但既然系统运行这种扩充用户态虚拟内存的方式,应该影响不会很大。这个方法简单快速,也不会引入新的bug,短期内最合适,所以最后选的是这个方法!

5、最后

       在Visual Studio中修改链接选项,可以直接将用户态虚拟内存从2GB扩充到3GB,可以有效的规避内存不够用的问题。这种方法简单方便,可以快速地解决问题。但最根本的还是要对内存进行优化,尽量减少对内存的占用,也能提高程序的执行效率。当然优化代码的过程中,也可能会引入这样那样的bug,需要根据时间和工作量评估可行性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1643263.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新手去做抖音小店,这七点千万别忽视!建议收藏!

大家好&#xff0c;我是电商小V 今天咱们就来详细的说一下新手操作抖音小店的几个通病&#xff0c;想要去做抖音小店的小伙伴千万要注意&#xff0c;一定要避免&#xff0c;不要踩坑&#xff0c; 第一点&#xff1a;新手刚去做抖音小店不赚钱的主要原因不是因为你选择了大类目&…

从零开始Hadoop安装和配置,图文手把手教你,定位错误(已部署成功)

文章目录 时间急的可以看速成&#xff0c;虚拟机和配置方法已给出&#xff0c;提供下载的为一台主节点一台分结点的虚拟机下载&#xff0c;只需进行ip地址更换即可 [现成Hadoop配置&#xff0c;图文手把手交你](https://blog.csdn.net/weixin_52521533/article/details/1328627…

7.string

目录 学库一定会看文档 1.Member functions string介绍 2.迭代器iterator 1.正向迭代器 2.反向迭代器 3.反向const 4.反向const 3.容量capacity 0.size(),capacity(),max_size(),length() 1.扩容机制&#xff08;vs和Linux g对比&#xff09; 2.clear&#xff08;&a…

从电商系统认识数据与数据的存储

相信各位读者一年不知道要多少次通过电商App浏览和购买商品。既然大家对电商系统都比较熟悉&#xff0c;我将以电商系统作为研究对象&#xff0c;进一步聊聊数据与数据存储的相关内容。 比如我们在某平台搜索“文件系统”这个关键字&#xff0c;想看看这方面的书籍。当我们输入…

环形链表面试题详解

A. 环形链表1 给你一个链表的头节点 head &#xff0c;判断链表中是否有环. 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置…

Typescript语法二

继承 继承是⾯向对象编程中的重要机制&#xff0c;允许⼀个类&#xff08;⼦类或派⽣类&#xff09;继承另⼀个类&#xff08;⽗类或基类&#xff09;的属性和⽅法。⼦类可以直接使⽤⽗类的特性&#xff0c;并根据需要添加新的特性或覆盖现有的特性。这种机制赋予⾯向对象程序良…

OpenCV的周期性噪声去除滤波器(70)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV如何通过梯度结构张量进行各向异性图像分割(69) 下一篇 :OpenCV如何为我们的应用程序添加跟踪栏(71) 目录 目标 理论 如何消除傅里叶域中的周期性噪声&#xff1f; 源代码 解释 结果 目…

C语言——指针的奥秘(1.0)

指针 一.内存和地址1.内存2.编址 二.指针变量和指针1.取地址操作符&#xff08;&&#xff09;2.指针变量和解引用操作符&#xff08;*&#xff09;1.指针变量2.拆解指针类型3.解引用操作符4.指针变量的大小 三.指针变量的类型和意义1.指针的解引用2.指针 - 整数3.void* 指针…

54.HarmonyOS鸿蒙系统 App(ArkTS)tcp socket套接字网络连接收发测试

工程代码https://download.csdn.net/download/txwtech/89258409?spm1001.2014.3001.5501 54.HarmonyOS鸿蒙系统 App(ArkTS)tcp socket套接字网络连接收发测试 import socket from ohos.net.socket; import process from ohos.process; import wifiManager from ohos.wifiMana…

redis的哨兵

文章目录 一、概念手动恢复redis主从复制的流程自动回复redis主从复制的流程 二、部署三、哨兵节点的作用演示四、哨兵节点的原理 一、概念 Redis Sentinel 相关名词解释 我主要说一个场景&#xff0c;就是我们上一篇讲到的redis主从复制会遇到的问题&#xff0c;朱姐带你如…

细粒度图像分类论文研读

细粒度图像分类论文研读 摘要Abstract1. 基于细粒度图像分类的视觉语义嵌入模型1.1 文献摘要1.2 创新点1.3 模型网络结构和方法1.3.1 问题陈述1.3.2 两级卷积神经网络1.3.3 局部化 CNN1.3.4 回归排序网络1.3.5 参数学习 1.4 实验1.4.1 数据集1.4.2 实验设置1.4.3 分类结果对比1…

3.SpringSecurity基本原理

SpringSecurity本质是一个过滤器链。十多个过滤器构成一个过滤器链。 这些过滤器在项目启动就会进行加载。每个过滤器执行放行操作才会执行下一个过滤器。 常见过滤器 FilterSecurityInterceptor 是一个方法级的权限过滤器&#xff0c;基本位于过滤器链的最底部。 Excepti…

图神经网络综述和学习路径

应用邻域 应用举例 应用层面&#xff08;节点&#xff0c;连接&#xff0c;子图&#xff0c;全图&#xff09; 概念区别 图神经网络本质上解决了表示学习的问题 可以把神经网络看作一个黑箱&#xff0c;图中的f函数 困难与挑战 现代的深度学习&#xff0c;如何把图输入到神经…

Qwik 和 Next.js 未来Web项目框架

Qwikover Next.js Qwik 是我进行 Web 项目开发的首选框架&#xff0c;而不是 Next.js 作为一名全栈工程师&#xff0c;我的前端之旅始于大约 10年前。从纯 JavaScript 和 jQuery 开始&#xff0c;然后转向了 KnockoutJS、AngularJS 和 GWT。React 出现&#xff0c; React 一直是…

IoTDB 入门教程 问题篇②——RPC远程连接IoTDB服务器失败

文章目录 一、前文二、发现问题三、分析问题四、检查6667端口是否监听所有IP五、检查ECS云服务器的安全组是否允许六、检查Linux防火墙是否允许 一、前文 IoTDB入门教程——导读 二、发现问题 使用本地IP127.0.0.1可以连接IoTDB服务器使用远程IPxx.xx.xx.xx却连接不到。提示你…

哥白尼高程Copernicus DEM下载(CSDN_20240505)

哥白尼数字高程模型(Copernicus DEM, COP-DEM)由欧洲航天局(European Space Agency, 简称ESA或欧空局)发布&#xff0c;全球范围免费提供30米和90米分辨率DEM。COP-DEM是数字表面模型(DSM)&#xff0c;它表示地球表面(包括建筑物、基础设施和植被)的高程。COP-DEM是经过编辑的D…

java发送请求-http和https

http和https区别 1、http是网络传输超文本协议&#xff0c;client---- http------ server 2、httpshttpssl证书&#xff0c;让网络传输更安全 &#xff0c;client---- httpssl------ server 3、ssl证书是需要客户端认可的&#xff0c;注意官方证书和jdk生成的证书的用户来使…

sql 中having和where区别

where 是用于筛选表中满足条件的行&#xff0c;不可以和聚类函数一起使用 having 是用于筛选满足条件的组 &#xff0c;可与聚合函数一起使用 所以having语句中不能使用select中定义的名字

【设计模式】13、template 模板模式

文章目录 十三、template 模板模式13.1 ppl13.1.1 目录层级13.1.2 ppl_test.go13.1.3 ppl.go13.1.4 llm_ppl.go13.1.5 ocr_ppl.go 十三、template 模板模式 https://refactoringguru.cn/design-patterns/template-method 如果是一套标准流程, 但有多种实现, 可以用 template …

nodejs的ws+vue3编写聊天室的demo

nodejs编写ws服务是非常简单高效的&#xff0c;nodejs有众多的实现ws的库&#xff0c;如ws,SocketIO等&#xff0c;nodejs的事件线程是单线程的&#xff0c;所以不要在事件线程内做阻塞性的操作&#xff0c;耗时的操作交给工作线程或者子进程操作。 我使用nodejsvue3实现了写了…