百度APP iOS端内存优化实践-内存管控方案

2023-05-16

在这里插入图片描述

01 背景

随着业务的发展,百度APP有很多大内存业务场景如直播、短视频、小程序、百度识图等,通过线上页面统计数据得知超过150M页面有40个,耗内存最多的页面有400M。单个页面不会有内存或者稳定性问题,但是当用户浏览了很多页面之后,累加起来内存已经很高了,再加上我们为了追求秒开,经常采用的思路是以空间换取时间,从而导致APP处于一个内存高水位状态,在这种情况下如果打开一个大内存页面,中低端机极大概率会出现OOM类型的崩溃。

内存管控方案应运而生,该方案重点解决的问题是在内存水位很高的情况下,保证APP稳定性又兼顾用户体验,延长APP使用时长同时避免OOM。

该技术方案在百度APP于22年Q1顺利上线,随着基础服务层和越来越多的业务线接入,尤其是OOM频发的页面接入后,在降低OOM率方面发挥了重大作用,效果非常明显。

02 技术方案综述

内存管控整体方案架构图如下所示:
在这里插入图片描述

  • 实时监控APP内存:在APP运行阶段不断监控内存变化。重点关注两个问题,第一,选取合适的能反映APP内存的指标,第二、实时性必须满足要求,同时不能引入额外的性能问题。

  • 页面内存预测:根据历史经验和线上数据,我们可以预测将要打开新页面后APP占用内存大小,结合当前内存我们可以实时计算出应用新开当前页面后自身占用的内存大小,举个例子,当前页面占用内存400M,通过线上历史经验数据我们知道新页面需要占用内存是300M,那么新开一个页面后,APP内存700M。

  • 内存水位判断:根据对当前APP内存状态的监控,能够判断出用户内存所处的水位状态,如安全水位和危险水位,安全水位是指当前APP内存足够,可完全按照业务需求分配内存,危险水位是指目前APP很容易出现OOM,必须马上释放内存缓存。

  • 频率控制:因为每隔3S做一次内存检测,当处于危险水位时,会通知APP各个模块做内存释放,但内存释放也是需要时间的,并且不一定会立马降低到安全水位,如果接下来还是每隔3S通知各模块做内存释放,其实是一种资源浪费,频繁的内存释放操作会给APP性能带来损耗,所以通过频率控制模块既能最大限度地释放内存,又实现APP性能最小损失。

  • 危险水位报警:当APP的内存处于危险水位的状态时,会向基础服务层和业务两个层面发送报警通知,对于基础服务层来说,百度APP主要做了图片内存和NSURLCache内存自动回收,全局生效;对于业务层来说,主要针对内存大户且OOM率较高的页面做了内存释放操作,如小程序页面,收到内存报警时,会将缓存的处于非活跃状态的页面做清理操作,对于其他业务同样道理,清理业务自身的数据缓存和其他内存缓存。

  • 主动降级:是指业务层在分配较大内存时,先判断当前APP所属的内存水位等级,若处于危险水位,业务做降级分配较小内存,若处于安全水位,做全量内存分配。目前百度APP的识图和数字人业务已接入此方案,对于百度识图场景,做多模态图片识别加载算法模型文件较大,处于危险水位时加载兜底模型,以业务能用为标准,其他场景类似。

03 与内存报警的区别

目前iOS系统中存在类似的方案,专业名称为内存报警机制,当设备可用内存下降到到危险状态时,Mach系统的pageout 守护程序会查询进程列表及其驻留页面数,向驻留页面数最高的进程发送NOTE_VM_PRESSURE ,被选中的进程会响应这个压力通知,本质上就是APP收到系统的didReceiveMemoryWarning 内存警告,APP释放部分内存达到降低手机内存负载的目标。有人会问iOS系统提供了内存报警通知,为什么我们还会做貌似类似的事情,这是因为我们对系统的内存报警机制做了如下两点补充

  • 内存报警机制是内存极其危险的时候才发出的,尤其是对于低端机而言非常致命,因为APP来不及释放内存到安全水位就已经OOM了。在实践开发过程中,对低端机(iPhone8以下)测试结果发现,当收到内存报警时,APP实际可使用内存(可用内存减去已用内存)没有超过100M,但是目前手百APP大于150M页面就有40个,当收到内存警告前后,随便打开上述40个大页面中的任何一个页面,APP根本没有来得及处理警报应用就会崩溃。相反,百度APP内存管控方案在制定危险水位时考虑到这种情况,适当预留了较大空间,让APP更从容地释放内存。

  • 内存报警机制没有提供获取APP实时内存状态的功能,在实践中经常会遇到大块内存分配的场景,较为常见场景如在中低端机端智能场景中,加载大模型到内存时,因为不知道内存当前处于危险状态还是安全状态,分配较大内存会出现内存峰值瞬时上涨到高点,中低端机手机设备直接OOM,在整个过程中也根本没有收到过内存报警。内存管控方案弥补了这一不足,通过实时获取内存状态,不同机型不同设备设置不同危险水位级别,在分配较大内存时,先判断APP内存状态,若处于危险水位时,业务线开发可以走降级逻辑,降低对内存消耗,减少OOM风险。

04 实时监控APP内存

百度APP实时监控内存采用如下方案:在子线程开启定时器,每隔3S去采样一次内存phys_footprint字段数据,以此作为衡量的内存的唯一指标,其他字段值一律不要获取,因为多增加一个变量会多增加CPU计算量。实践数据表明,第一、单次获取phys_footprint耗时小于1us,每隔3S获取phys_footprint没有引起CPU占比的涨幅,也就是说不会带来性能问题;第二、3S的采样周期实时性完全满足我们工程的要求,正常情况下,开启一个页面到页面可交互需要1.5S+,采样周期如果太长,会存在页面内存已经飙升但是还没来得及做管控,采样周期太短会浪费过多的CPU资源。

为什么我们选用phys_footprint作为内存衡量指标,而不用其他字段,需要重点解释一下。iOS端所有的内存相关指标都集中在task_vm_info结构体中,下载XNU最新开源代码(https://opensource.apple.com/source/xnu/),代码路径:osfmk/mach/task_info.h,具体字段值如下所示:

struct task_vm_info {  
    mach_vm_size_t  virtual_size;       /* virtual memory size (bytes) */
  integer_t       page_size;
  mach_vm_size_t  resident_size;      /* resident memory size (bytes) */
    /* 省略 */
  mach_vm_size_t  phys_footprint;
    /* 省略 */
}

iOS开发演变的这几年历程中,受Android端内存指标影响,我们先后使用过各种内存指标,常见的如virtual_size( 虚拟内存)、resident_size(驻留内存)和phys_footprint,那究竟使用哪个指标是合理的?我们知道iOS使用的是低内存清理机制叫Jetsam,这个机制有点类似于Linux的“Out-of-Memory”杀手,当内存压力过大时,Jetsam会把一些优先级不高或者占用内存过大的进程杀掉。就是说内存处于危险状态时Jetsam决定kill哪个进程,因此Jetsam衡量内存水位指标绝对是众多内存指标中最为合理的一项,接下来我们看Jetsam机制源码。

我们再次回到XNU源码中,查看代码bsd/kern/kern_memorystatus.c,重点查看函数 memorystatus_kill_hiwat_proc,这是jetsam核心代码,用于kill高内存分配进程的关键函数,具体实现如下所示:

static boolean_t
memorystatus_kill_hiwat_proc(uint32_t *errors, boolean_t *purged, uint64_t *memory_reclaimed)
{
    next_p = memorystatus_get_first_proc_locked(&i, TRUE);
  while (next_p) {
        /* 省略 */
    footprint_in_bytes = get_task_phys_footprint(p->task);
    skip = (footprint_in_bytes <= memlimit_in_bytes);
    if (skip) {
      continue;
    } else {
        memorystatus_kill_proc(p, kMemorystatusKilledHiwat, jetsam_reason, &killed, &footprint_in_bytes); 
           /* 省略 */
        }  
}

首先通过memorystatus_get_first_proc_locked去优先级队列里面取出优先级最低的进程,如果内存超过阈值,将通过memorystatus_kill_proc杀掉这个进程,否则跳过取下一个进程。我们看到Jetsam是通过 get_task_phys_footprint方法获取内存水位来决定是不是需要kill该进程,因此使用phys_footprint作为APP内存指标是最合适的。

关于 phys_footprint 的定义,我们回到 XNU 源码中,查看代码 osfmk/kern/task.c ,有phys_footprint 的注释定义。

*   Physical footprint: This is the sum of: 
*     + (internal - alternate_accounting) 
*     + (internal_compressed - alternate_accounting_compressed) 
*     + iokit_mapped 
*     + purgeable_nonvolatile 
*     + purgeable_nonvolatile_compressed 
*     + page_table

phys_footprint = (internal - alternate_accounting) + (internal_compressed - alternate_accounting_compressed) + iokit_mapped + purgeable_nonvolatile + purgeable_nonvolatile_compressed + page_table 。

字段
具体含义
internal
在iOS中表示的就是resident_size驻留内存 
internal_compressed
iOS 上没有交换空间机制,取而代之使用Compressed memory,是在内存紧张时能够将最近使用过的内存占用压缩至原有大小的一半以下,并且能够在需要时解压复用
iokit_mapped
io设备映射占用的内存,其实是不能使用purgeable memory的部分
alternate_accounting
iokit映射占用的dirty页
page_table
虚拟地址映射表内存
purgeable_nonvolatile
下面重点介绍

purgeable内存是iOS系统为开发者提供的一层cache机制,分为volatile、empty和non_volatile三种类型,volatile表示该内存资源是暂时不被使用的,系统将在内存吃紧的时候回收掉它,使用这种类型资源前要查询是否已经无效了(变成empty状态);empty表示该内存资源明确不用了需要立即释放;non_volatile表示该内存资源一直有用,不能被回收。volatile和empty状态的资源不计入进程自己的mem footprint,它算系统的cache内存,nonvolatile会算自己进程的内存,被虚拟内存系统回收时不会被换出到磁盘,所以phys_footprint在计算内存时,只计算了nonvolatile类型,对于volatile、empty没做计算。

05 页面内存预测

为了能够更精准的对页面的内存进行分析和预测,我们在实时内存监控的基础上,开发了页面内存预测方案。具体来说,在前面通过定时器我们知道了每隔3S手机APP内存状态,本方案通过经验数据直接预测未来一段时间内存的涨幅,让业务线可以更加从容的释放内存。我们知道当新打开一个页面时存在内存飙升的情景,这个时候3S的采样周期未到,内存已经上涨很多,内存管控方案还未生效APP极有可能已经OOM了。我们的方案是通过页面内存计算,在打开新页面前一刻, 就知道接下来页面内存可能会涨到多少,如果进入危险水位,实时释放内存以降低OOM率,通过这种精细化处理进一步提前降低内存峰值。

页面内存计算方案如下所示,首先,当前页面是P1页面,当有页面跳转发生,将要通过push操作进入到P2页面时,记录当前百度APP内存phys_footprint值为M1,当从P2页面同样发生跳转到其他页面时,记录百度APP内存phys_footprint值为M2,那么M2-M1为P2页面内存。

注意,我们只通过push方式统计了页面内存,没有通过pop方式统计,有两个原因,第一、通过线上数据发现,pop方式时因页面已经打开,并且会创建单例导致内存统计存在很多badcase,push方式时页面从未创建也不会有单例,数据相对准确;第二、通过push方式已经可以覆盖所有页面了,pop方式不需要统计。
在这里插入图片描述

06 制定内存水位

关于内存水位的制定直接决定了本方案实际收益的大小,水位阈值制定太小会导致频繁的内存管控影响业务效果,水位阈值制定的太大,与实际的Jetsam水位线偏离过大,导致内存管控无法生效,可能会出现APP已经OOM了,管控方案还没生效,水位线的制定非常关键。

关于危险水位线的制定,必须结合Jetsam原理,目前苹果官方没有公开Jetsam水位的文档,业界有如下方法解决方案。

丨6.1 通过Jetsam日志获取

具体来说从手机"设置->隐私->分析与改进->分析数据"这条操作路径中,可以拿到JetsamEvent 开头的日志。这些日志中就可以获取一些关于 App 的内存信息,查找崩溃原因时需要关注 per-process-limit 部分的 rpages,其中rpages代表进程占用的内存页数量。pageSize代表当前设备物理内存页的大小,在 JetsamEvent 开头的系统日志里可以找到 pageSize 的值,那么pageSize * rpage的值代表目前该进程OOM时使用的内存大小,可作为进程可用内存的上限。

实际操作过程中,发现此方法可操作性不强,因为同一台手机不同的JetsamEvent日志rpages值变化太大,用iphone12的测试结果显示,从400到800都有,pageSize是固定值16384Byte,按照最高值计算当前 App 的内存限制值:pageSize * rpages / 1024 /1024 =16384 * 800 / 1024 / 1024 = 12.5M,按这个结果iphone12最大的内存阈值是12.5M,置信度明显有问题。

在这里插入图片描述

丨6.2 通过XNU源码获取内存水位阈值

首先必须越狱手机获取root权限,通过XNU源码中的数据结构、宏定义和函数获取OOM阈值,参考XNU最新开源代码(https://opensource.apple.com/source/xnu/),代码路径:bsd/sys/kern_memorystatus.h,关键数据结构memorystatus_priority_entry,定义如下,其中pid代表进程标识,priority代表JetSam中的优先级,limit就是我们要找的水位线上线。同时,在文件kern_memorystatus.h有如下跟进程优先级相关的宏命令,其中通过MEMORYSTATUS_CMD_GET_PRIORITY_LIST宏定义可以获取进程的优先级列表以及每个进程的内存水位线。

typedef struct memorystatus_priority_entry {
  pid_t pid;
  int32_t priority;
  uint64_t user_data;
  int32_t limit;
  uint32_t state;
} memorystatus_priority_entry_t;

#define MEMORYSTATUS_CMD_GET_PRIORITY_LIST            1
#define MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES      2
#define MEMORYSTATUS_CMD_GET_JETSAM_SNAPSHOT          3
#define MEMORYSTATUS_CMD_GET_PRESSURE_STATUS          4
 /* 省略 */  

最后通过调用系统函数memorystatus_control的实现可获取memorystatus_priority_entry结构体值,其中limit字段代表水位线, 代码路径:bsd/kern/kern_memorystatus.c

int memorystatus_control(struct proc *p __unused, struct memorystatus_control_args *args, int *ret)
     /* 省略 */
     switch (args->command) {
  case MEMORYSTATUS_CMD_GET_PRIORITY_LIST:
    error = memorystatus_cmd_get_priority_list(args->buffer, args->buffersize, ret);
    break;
     /* 省略 */    
}

实践证明这种方法是可行的,唯一缺点是需要获取root权限,我们要获取不同机型的内存阈值,需要将这些设备全部越狱。

丨6.3 百度APP采用的技术方案

百度APP采用的方案是综合百度APP自身的线上业务数据,采用主动触发OOM获取内存阈值方案,结合多方数据最后确定内存危险水位阈值。

丨6.3.1 内存数据摸底

通过线上内存采样打点,获取了百度APP不同机型在使用过程中的内存值,然后经过服务端数据聚合,我们明确知道了百度APP在没有发生OOM情况下不同机型的内存最大值,这份线上数据很重要,虽然不是内存阈值的,但是内存阈值肯定是高于该值的。

丨6.3.2 页面内存数据统计

技术方案在第五节做过详细介绍,这儿不再赘述,通过服务端对页面内存数据挖掘后,我们明确知道了不同机型新开一个页面时最大的内存涨幅。

丨6.3.3 主动触发OOM获取内存值

开启定时器任务每隔1S分配20M内存,示例代码如下所示:

int size = 20 * 1024 * 1024;
char *info = malloc(size);
memset(info, 1, size);

同时监控内存变化,在控制台输出,随着可用内存越来越少,触发Jetsam机制,直到发生OOM,从而得到OOM前内存阈值。

(int64_t)memoryUsage {
    int64_t memoryUsageInByte = 0;
    struct task_vm_info info;
    mach_msg_type_number_t size = TASK_VM_INFO_COUNT;
    kern_return_t kerr = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &info, &size);
    if (kerr == KERN_SUCCESS ) {
        memoryUsageInByte = info.phys_footprint;
    }
    return memoryUsageInByte;
}

丨6.3.4 确定内存管控危险水位阈值

经过前面三个步骤,我们获取了不同机型的三个阈值,分别是内存数据摸底阈值、页面内存阈值、主动触发OOM获取的阈值,为了让业务更从容地释放内存, 内存管控阈值为主动触发OOM获取的阈值减去页面内存阈值,如果该值小于内存数据摸底阈值,那么内存数据摸底阈值就是该机型内存管控阈值。

百度APP采用的这个技术方案不需要越狱手机,通过主动触发OOM获取的阈值体现了Jetsam机制,更具有可操作性;同时结合自身线上数据,针对手百场景定制化挖掘。

07 总结

最后,总结百度APP内存管控方案具有如下特点:

  • 针对不同机型制定了相应的内存水位可以更加从容地释放内存。本技术方案结合Jetsam机制和百度APP线上内存数据,制定了iPhone各机型允许使用的内存水位线,给业务和框架更大的空间释放和清理内存。

  • 实时内存监控和精细化页面内存预测,在实时内存监控的基础上,开发了页面级的内存度量方案,可以估算出用户在新开一个页面内存涨幅多少,在未来一段时间内存会不会达到危险水位。

  • 内存管控方案提供主动和被动通知两种方式获取内存水位状态,实现了各业务层根据手机内存情况实时降级,时效性更强,跟之前服务端降全量降级方案相比,更加灵活,性能更好。

该方案上线后,随着Q2基础服务层和业务线接入,实现OOM降低一半的收益,并且业务层接入成本很低,后续会推动更多内存大户和OOM频发的页面接入。感谢各位阅读至此,如有问题请不吝指正。

———— END————

参考资料

[1] OOM探究:XNU 内存状态管理:https://www.jianshu.com/p/4458700a8ba8

[2]XNU源码:https://opensource.apple.com/source/xnu/

[3]《深入解析Mac OS X & iOS操作系统》

[4]iOS Out-Of-Memory 原理阐述及方案调研:https://juejin.cn/post/6844903749836603400#heading-7

推荐阅读

Ernie-SimCSE对比学习在内容反作弊上应用

质量评估模型助力风险决策水平提升

合约广告平台架构演进实践

AI技术在基于风险测试模式转型中的应用

Go语言躲坑经验总结

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

百度APP iOS端内存优化实践-内存管控方案 的相关文章

  • ubuntu与windows互传文件的3种方法

    一般在进行编程作业的时候 xff0c 我们会采用 开发在Windows中编辑源代码 xff0c 在linux中编译 执行源代码 这往往需要需要将在Windows下编辑好的源代码上传到linux系统种进行编译 怎么来进行上传呢 xff1f 其
  • ubuntu下如何设置环境变量

    一 设置环境变量的三种方法 1 1 临时设置 export PATH 61 home yan share usr local arm 3 4 1 bin PATH 1 2 当前用户的全局设置 打开 bashrc xff0c 添加行 xff1
  • ssh免密登录设置方法

    1 前提条件 主机A xff0c 用户名为aris xff0c IP地址为192 168 1 1主机B xff0c 用户名为leon xff0c IP地址为192 168 1 2这两台主机上均安装了SSH服务器 xff0c 且已经打开ssh
  • 软考高项你想要的全在这

    2021年准备参加软考获取高级职业技术资格认证的小伙伴咱们约起吧 xff1f xff01 自软考系列文章发表之后有很多准备参加软考的小伙伴加我微信 xff0c 关注我的微博 xff0c 也有很多因此成了好朋友 xff0c 甚至是同事 自前年
  • Makefile语法及通用模板

    简介 xff1a 本文主要讲解了在开发常规项目时 xff0c 用于自动化部署生成目标文件的Makefile 对其包含的主要语法进行了讲解 xff0c 最后给出了一个项目通用的Makefile模板 xff0c 以帮助大家理解 1 Makefi
  • ubuntu镜像源的配置

    摘要 xff1a 你是否遇到过按照网上教程更改了自己的镜像源之后 xff0c 貌似还是不兼容 xff0c 许多安装包还是下不了 xff1f 其实不是他们写的教程有错误 xff0c 而是你没用根据自己使用的ubuntu的版本去正确配置镜像源
  • Linux中与“内核模块”相关的数据结构

    摘要 本文详细解释了linux中与模块相关的内核数据结构 xff0c 便于大家在学习理解内核源码或驱动编程中理解相应代码和思想 三 内核模块相关的数据结构 目录 THIS MODULE宏module结构体module use 3 1 THI
  • Linux内核中与“文件系统”相关的数据结构

    文件系统相关的数据结构 4 1 file结构体 文件结构体代表一个打开的文件 xff0c 系统中的每个打开的文件在内核空间都有一个关联的struct file 它由内核在打开文件时创建 xff0c 并传递给在文件上进行操作的任何函数 在文件
  • 【可解释AI】图神经网络的可解释性方法及GNNexplainer代码示例

    图神经网络的可解释性方法及GNNexplainer代码示例 GNNExplainerIntroductionModelSingle instance explanations xff08 Explanation via Structural
  • 文本编辑器VI命令详解

    目录 一 xff1a 文本编辑器概述 1 文本编辑器含义 2 文本编辑器的作用 3 Linux中最常见的文本编辑器 二 vi编辑器的工作模式 1 vi编辑器的工作模式 2 各模式之间的切换 三 xff1a 命令模式概述 1 命令模式常用操作
  • Linux中与“内核安全”相关的数据结构

    五 内核安全相关数据结构 5 1 security operations结构体 这是一个钩子函数的指针数组 xff0c 其中每一个数组元素都是一个SELINUX安全钩子函数 xff0c 在2 6以上的内核中 xff0c 大部分涉及安全控制的
  • 洛谷 P3366 【模板】最小生成树

    题目描述 如题 xff0c 给出一个无向图 xff0c 求出最小生成树 xff0c 如果该图不连通 xff0c 则输出orz 输入输出格式 输入格式 xff1a 第一行包含两个整数N M xff0c 表示该图共有N个结点和M条无向边 xff
  • 关于网站最近出现504错误的总结,too open many files in system

    如果你有耐心看完这篇文章 xff0c 也许会给你带来真正的益处 网站出现504错误 xff0c 如果你用阿里云CDN的话还会报 504 Gateway Time out The gateway did not receive a timel
  • Manjaro21安装VNC,Win10远程连接manjaro桌面

    manjaro安装tigervnc xff0c win10使用VNC viewer TigerVNC 简体中文 ArchWiki archlinux org https wiki archlinux org title TigerVNC E
  • Proxmox虚拟环境搭建

    一 Proxmox VE简介 ProxmoxVE 是一个完整的 开源的企业虚拟化服务器管理平台 它在单个平台上紧密集成了 KVM 管理程序和 Linux 容器 LXC 软件定义的存储和网络功能 通过集成的基于 web 的用户界面 xff0c
  • HEX2DEC存储过程实现

    数据库当前有十进制转换为十六进制的函数hex 函数 xff0c 却没有十六进制转换为十进制的函数 xff0c 只能自己定义一个hex2dec xff0c 存储过程如下 xff1a span class token keyword drop
  • SQLite数据类型引起的问题——全数字字符串使用varchar出现错误

    问题 xff1a 项目中需要把某些数据保存到Android的数据库中 xff0c 因为保存的字符串全部为数字形式 xff0c SQLite把部分字符串自动转化为了科学技术法导致数据显示异常 xff0c 同时还把一些开头为0的字符串自动去掉了
  • IOS 自定义UIAlertController

    自定义UIAlertController xff1a 首先展示效果图 1 创建一个新的类来管理弹出的视图 继承于UIView 2 传建一个xib文件来自定义弹出视图 xff08 注意创建过后一定要将xib的class关联 xff09 3 在
  • python把txt文件里重复数据去重代码

    有时候会发现txt文件里有很多重复数据 xff0c 这里自写了一个去重的python程序 xff0c 供学习使用 xff01 def quchong print 39 39 50 print 39 导入txt文件中 39 num 61 0
  • ERROR 1064 (42000): You have an error in your SQL

    对于新手来说 xff0c MySQL数据库 xff0c 在命令行使用sql语句进行建库 xff0c 查库 xff0c 建表 xff0c 查表 时 xff0c MySQL 报错 xff1a ERROR 1064 42000 You have

随机推荐

  • 【图神经网络】GNNExplainer代码解读及其PyG实现

    GNNExplainer代码解读及其PyG实现 使用GNNExplainerGNNExplainer源码速读前向传播损失函数 基于GNNExplainer图分类解释的PyG代码示例参考资料 接上一篇博客图神经网络的可解释性方法及GNNexp
  • python之自动发送微信消息

    这篇文章主要是总结最近写自动发送微信消息的python代码时所接触的两个库 pyautogui和pyperclip的用法 在网上找了很多能实现发送微信消息的方法 xff0c 其中有使用itchat和wxpy库来实现的 xff0c 尝试过后发
  • CSU1646: HearthStone(DP)

    Description Henry十分钟爱炉石传说 Heart Stone 这款有趣的桌面卡牌游戏 我们简化的游戏规则如下 xff1a 游戏由两人对战 xff0c 出牌并尽量对对方造成最大的伤害 xff0c 一共进行 r轮 前10轮 xff
  • System.DllNotFoundException:“无法加载 DLL“XXX.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。”

    System DllNotFoundException 无法加载 DLL XXX dll 找不到指定的模块 异常来自 HRESULT 0x8007007E 一般这种情况需要按是否安装完整了vc的运行时 xff0c 可以尝试安装 VC运行库合
  • Arch-004ArchLinux搜狗输入法安装

    搜狗输入法 1 sudo pacman Rsn fcitx im fcitx configtool 2 sudo pacman S fcitx lilydjwg git fcitx sogoupinyin 3 sudo pacman S f
  • AArch64中va_list/va_start/va_arg/...的实现

    版权声明 xff1a 本文为笔者本人 ashimida 64 的原创文章 xff0c 遵循CC 4 0 BY SA版权协议 xff0c 转载请附上原文出处链接及本声明 原文链接 xff1a https blog csdn net lidan
  • 51单片机外部中断示例

    void Usart INT0 init TMOD 61 0X21 TH1 61 0XFD TL1 61 0XFD SM0 61 0 SM1 61 1 REN 61 1 TR1 61 1 ES 61 1 串口中断影响外部中断0 这句话会让程
  • Hive深入浅出UDTF

    前面两篇文章我们分析了UDF和UDAF的原理以及实现思路 xff0c 这一节我们介绍另外一种UDF UDTF User Defined Table Generating Functions xff0c 是用来解决输入一行输出多行的需求的 x
  • STM32学习(3)-GPIO相关寄存器,引脚复用和重映射,点亮LED小灯(库函数、寄存器)

    参考STM32中文参考手册 一 GPIO相关配置寄存器 每组 如GPIOA GPIOB GPIO端口的寄存器包括 1 1 端口配置寄存器 由于STM32是32位的寄存器 xff0c 一个寄存器只有32位 xff0c 但是一个I O口需要4个
  • Template parse errors: Can't bind to 'ngStyle' since it isn't a known property of 'div'. ("

    1 背景 开发个公共组件 xff0c 在组件中使用指令一直报错 template 96 lt div class 61 34 content text bgp 34 gt lt div class 61 34 content text 34
  • linux mount 远程服务器共享目录

    NFS是文件系统 在网络存储方面我们应该有所了解 那么针对NFS服务器的安装和设置我们来详细介绍一下 首先让我们看一下NFS服务器的安装步骤 一 NFS服务器的安装 检查linux系统中是否安装了nfs utils和portmap两个软件包
  • 【每日一题】969. 煎饼排序

    969 煎饼排序 题目描述解决方案 xff1a 类选择排序法代码 xff1a Python 题目来源 xff1a Leetcode 原文链接 xff1a https mp weixin qq com s jboDC0R oYAy ssCXp
  • 让Num Lock默认开启

    让Num Lock默认开启 2008年11月18日 星期二 10 46 A M 1 对于2000或者XP操作系统 xff0c 登陆前NUM LOCK默认为关闭 xff0c 此为正常现象 xff0c 若用户需要此功能 xff0c 则需更改注册
  • Windows下使用Sublime Text配置C++编译环境

    1 打开Sublime xff0c 选择Tools gt Build System gt New Build System 2 将以下代码复制粘贴到新文件中去 34 span class hljs attribute path span 3
  • 一步步将ffmpeg封装golang/cgo库

    欢迎访问博客原文 xff1a https lightfish cn 2018 12 24 ffmpeg cgo 前言 继上一篇 ffmpeg音视频C编程入门 使用高性能的C语言进行音视频的处理 xff0c 比较执行效率比较高 xff0c 但
  • 十六.Spark SQL之读取复杂的json数据

    第一步 准备json数据 test json 34 name 34 34 liguohui 34 34 nums 34 1 2 3 4 5 34 name 34 34 zhangsan 34 34 nums 34 6 7 8 9 10 te
  • “当前不会命中断点 还没有为该文档加载任何符号”问题的解决

    今天在实验室的电脑上调试程序出现了 当前不会命中断点 还没有为该文档加载任何符号 断点失效的情况 xff0c 是调用的静态库中断点失效 xff0c 但程序在我自己电脑上是可以正常打断点的 按照网上的方法试过没有成果 xff0c 但是启发了我
  • 【经验分享】设置电脑定时开关机

    文章目录 1 定时开机设置 xff08 BIOS固件设置 xff09 2 定时关机设置 放长假回家 xff0c 不想拷贝资料 xff0c 因此打算用todesk远程连接办公 但是工位电脑一直开着 xff0c 还不能睡眠 xff0c 担心会过
  • AirSim多台无人机第一视角键盘控制进阶版

    AirSim多台无人机第一视角键盘控制进阶版 目录 AirSim多台无人机第一视角键盘控制进阶版本文实现的效果前言一 环境依赖二 图像读取与显示1 使用的API2 实时显示的一种方法 三 键盘控制改进总结 本文实现的效果 前言 本篇文章实现
  • 百度APP iOS端内存优化实践-内存管控方案

    01 背景 随着业务的发展 xff0c 百度APP有很多大内存业务场景如直播 短视频 小程序 百度识图等 xff0c 通过线上页面统计数据得知超过150M页面有40个 xff0c 耗内存最多的页面有400M 单个页面不会有内存或者稳定性问题