Linux mmap系统调用视角看缺页中断

2023-11-13

问题

1. mmap具体是怎么实现比read/write少一次内存copy的

2.mmap共享映射和私有映射在内核实现的时候到底有什么区别

3.mmap的文件映射和匿名映射在内核实现的时候到底有什么区别

4.父子进程的COW具体怎么实现的

概述

实际开发过程中经常使用或者看到mmap函数,具体细节可以man mmap查看相关细节。这个系统调用是个多面手,应用空间申请内存(比如glibc库申请大内存使用的是mmap),还是读写大文件,链接动态库,多进程间共享内存都可以看到mmap的身影,要想真正的理解这个系统一方面是从这几种使用场景的需求上理解mmap,更重要的必须基于内核源码,深入剖析其每个参数具体对应的内核实现。

 内存拷贝次数

以mmap映射文件场景来讲,mmap读写文件与read/write的相比少一次内存拷贝,如果想真正理解这句话最好亲自去看下read/write系统调用的实现流程。以read系统调用来讲其声明如下:

NAME
       read - read from a file descriptor
SYNOPSIS
       #include <unistd.h>
       ssize_t read(int fd, void *buf, size_t count);

传入一个用户态空间的虚拟地址指针buf,最终内核实现的时候要将文件内容copy到该buf中,我们的都知道内核为了加速读写文件速度会在内核中创建page cache内存(不考虑direct io),那么文件内容首先是读取到了内核的page cache内存中,page cache再拷贝到用户态地址buf当中而mmap的内核page直接跟用户态地址实现映射,那么只要缺页异常时候(文件缺页异常读取数据时mm/filemap.c::filemap_fault函数实现)将数据读取到对应的page中,自然用户态虚拟地址就可以读取到(因为用户态的虚拟地址通过页表直接映射了filemap_fault缺页中断生成的page)。

重点:mmap和read/write生成的page有什么区别?

我们看到mmap和read/write系统调用在内核态都会创建物理页page。mmap是缺页中断时候创建的,如果匿名映射(MAP_ANON)创建的匿名页面;如果文件映射创建的file-back page页面;这两种页面都通过用户态页表完成映射。而read/write系统调用创建的page则不同,这种page cache从某种角度来讲是"临时工",因为并没有用户态页表映射该page,write函数为例,内核系统调用实现的时候只把用户态buf copy给"临时工" page cache返回即可。那么临时工是怎么体现的?

read/write既然没有通过用户态页表,而内核把用户态buf拷贝给内核中的page cache又必须使用内核态虚拟地址,最终内核是通过kmap将page cache临时映射到内核虚拟地址:

//write系统调用会调用到该函数
ssize_t generic_perform_write(struct file *file,
				struct iov_iter *i, loff_t pos)
{
    ...
    //iov_iter封装了用户态地址buf,该函数将用户态buf copy到内核page cache中
	copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
    ...
}

size_t iov_iter_copy_from_user_atomic(struct page *page,                                                                                                                 
        struct iov_iter *i, unsigned long offset, size_t bytes)
{
    //通过kmap_atomic将内核page cache临时映射到内核态虚拟地址
    char *kaddr = kmap_atomic(page), *p = kaddr + offset;
    if (unlikely(!page_copy_sane(page, offset, bytes))) {
        kunmap_atomic(kaddr);
        return 0;
    }
    if (unlikely(i->type & ITER_PIPE)) {
        kunmap_atomic(kaddr);
        WARN_ON(1);
        return 0;
    }
    iterate_all_kinds(i, bytes, v,
        copyin((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len),
        memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page,
                 v.bv_offset, v.bv_len),
        memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len)
    )
    //因为是临时映射的,使用完该虚拟地址通过kunmap,因为这段虚拟地址还是有限的(32位应该是4M)
    kunmap_atomic(kaddr);
    return bytes;
}

通过上面场景我们同时也学习到kmap的典型使用场景,经常中文书籍中将kmap翻译成“永久映射”这完全是一种误导,恰恰相反,kmap使用场景是临时映射。

对于mmap这种文件读写情况不太想画图了,引用网络上一张图把:

mmap函数参数详解
NAME
       mmap, munmap - map or unmap files or devices into memory
SYNOPSIS
       #include <sys/mman.h>
       void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);
       int munmap(void *addr, size_t length);
  • prot : 设置内存映射区域vma的读写属性(vma中的vma_flags),最终也会影响页表项pte的读写属性。取值范围:
PROT_EXEC  Pages may be executed.
PROT_READ  Pages may be read.
PROT_WRITE Pages may be written.
PROT_NONE  Pages may not be accessed.
  • flags: 设置映射共享等属性。比如MAP_SHARED,MAP_PRIVATE,MAP_ANONYMOUS等。

PRIVATE:私有意味着修改内容触发写时复制,进程独自拥有不共享物理page。

MAP_SHARED:何谓共享,即缺页时不会触发写时复制,只要在原来的page内容上修改即可。分为文件共享和匿名共享:

文件共享其中任何已进程的改动其他进程可见(因为多个进程映射的是一样的物理page,自然互相可见),且内容的修改会同步磁盘文件

匿名共享:跟文件共享的区别没有映射磁盘文件,多进程之间还是映射一样的物理page,所以也可以互相可见,经常用来进程间通信。内核底层通过shmem实现。

MAP_PRIVATE: 何谓私有,修改页面触发写时复制,这样每个进程有自己独立的物理内存page,也就是私有。分为文件私有和匿名私有:

文件私有:一个进程修改文件会触发写时复制,其他进程不会看到映射内容的改变,修改内容也不会回写磁盘,最常见的场景是加载动态库。

匿名私有:不映射文件,修改内容触发写时复制。

mmap内核系统调用源码剖析之prot和flags

我们看下flags和prot两个参数具体是怎么影响vma和pte的:

mm/mmap.c

unsigned long do_mmap(struct file *file, unsigned long addr,
			unsigned long len, unsigned long prot,
			unsigned long flags, unsigned long pgoff,
			unsigned long *populate, struct list_head *uf)
{
	...
	/* Do simple checking here so the lower-level routines won't have
	 * to. we assume access permissions have been handled by the open
	 * of the memory object, so we don't do any here.
	 */
    //prot是mmap函数的prot参数,下面函数将prot转换成vm_flags相关的flag
	vm_flags = calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) |
			mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;

	if (file) {
		...
		switch (flags & MAP_TYPE) {
		case MAP_SHARED:
			/*
			 * Force use of MAP_SHARED_VALIDATE with non-legacy
			 * flags. E.g. MAP_SYNC is dangerous to use with
			 * MAP_SHARED as you don't know which consistency model
			 * you will get. We silently ignore unsupported flags
			 * with MAP_SHARED to preserve backward compatibility.
			 */
			flags &= LEGACY_MAP_MASK;
			fallthrough;
		case MAP_SHARED_VALIDATE:
			...
			vm_flags |= VM_SHARED | VM_MAYSHARE;
			...
		case MAP_PRIVATE:
			...
			break;

		default:
			return -EINVAL;
		}
	} else {
		switch (flags & MAP_TYPE) {
		case MAP_SHARED:
			...
			vm_flags |= VM_SHARED | VM_MAYSHARE;
			break;
		case MAP_PRIVATE:
			/*
			 * Set pgoff according to addr for anon_vma.
			 */
			pgoff = addr >> PAGE_SHIFT;
			break;
		default:
			return -EINVAL;
		}
	}
	...
	addr = mmap_region(file, addr, len, vm_flags, pgoff, uf);
	...
	return addr;
}

unsigned long mmap_region(struct file *file, unsigned long addr,
        unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
        struct list_head *uf)
{
    ...
    vma->vm_mm = mm;
    vma->vm_start = addr;
    vma->vm_end = addr + len;
    vma->vm_flags = vm_flags;
    //将vm_flags转换成vm_page_prot,看下面mk_pte函数知道,vm_page_prot最终会影响页表项
    //读写属性。
    vma->vm_page_prot = vm_get_page_prot(vm_flags);
    vma->vm_pgoff = pgoff;
    ...
    if(file) {
        ...
        //触发fs中的mmap,比如ext4_file_mmap
        call_mmap(...);
    }
    ...
}

//内核缺页时候创建pte一般调用mk_pte函数,就是通过vma->vm_page_prot生成pte的相关flag
//比如匿名缺页中断:
static int do_anonymous_page(struct vm_fault *vmf)
{
    ...
    //如果vm_flags没有设置
    entry = mk_pte(page, vma->vm_page_prot);
    ...
}

 cal_vm_prot_bits转换prot的逻辑也简单,我们知道prot取值为PROT_READ/PROT_WRITE/PROT_EXEC,该函数把prot分别兑换成VM_READ/VM_WRITE/VM_EXEC。

总结:最终vm_flags融合了读写相关的属性(来自cal_vm_prot_bits转换的mmap函数的prot参数)和共享属性(源自mmap函数flag参数),最终vm_flags影响vma和pte的flag。

缺页中断流程层次图

 源码:


/*
 * These routines also need to handle stuff like marking pages dirty
 * and/or accessed for architectures that don't do it in hardware (most
 * RISC architectures).  The early dirtying is also good on the i386.
 *
 * There is also a hook called "update_mmu_cache()" that architectures
 * with external mmu caches can use to update those (ie the Sparc or
 * PowerPC hashed page tables that act as extended TLBs).
 *
 * We enter with non-exclusive mmap_lock (to exclude vma changes, but allow
 * concurrent faults).
 *
 * The mmap_lock may have been released depending on flags and our return value.
 * See filemap_fault() and __lock_page_or_retry().
 */
static vm_fault_t handle_pte_fault(struct vm_fault *vmf)
{
	pte_t entry;
    ...

	if (!vmf->pte) {
		if (vma_is_anonymous(vmf->vma))
			return do_anonymous_page(vmf);
		else
			return do_fault(vmf);
	}

	if (!pte_present(vmf->orig_pte))
		return do_swap_page(vmf);

	if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma))
		return do_numa_page(vmf);

	vmf->ptl = pte_lockptr(vmf->vma->vm_mm, vmf->pmd);
	spin_lock(vmf->ptl);
	entry = vmf->orig_pte;
	if (unlikely(!pte_same(*vmf->pte, entry))) {
		update_mmu_tlb(vmf->vma, vmf->address, vmf->pte);
		goto unlock;
	}
	if (vmf->flags & FAULT_FLAG_WRITE) {
		if (!pte_write(entry))
			return do_wp_page(vmf);
		entry = pte_mkdirty(entry);
	}
	entry = pte_mkyoung(entry);
	if (ptep_set_access_flags(vmf->vma, vmf->address, vmf->pte, entry,
				vmf->flags & FAULT_FLAG_WRITE)) {
		update_mmu_cache(vmf->vma, vmf->address, vmf->pte);
	} else {
		/* Skip spurious TLB flush for retried page fault */
		if (vmf->flags & FAULT_FLAG_TRIED)
			goto unlock;
		/*
		 * This is needed only for protection faults but the arch code
		 * is not yet telling us if this is a protection fault or not.
		 * This still avoids useless tlb flushes for .text page faults
		 * with threads.
		 */
		if (vmf->flags & FAULT_FLAG_WRITE)
			flush_tlb_fix_spurious_fault(vmf->vma, vmf->address);
	}
unlock:
	pte_unmap_unlock(vmf->pte, vmf->ptl);
	return 0;
}
调用栈(以匿名页缺页中断为例):
#0  0xffffffff813988ff in do_anonymous_page (vmf=<optimized out>) at mm/memory.c:4409
#1  handle_pte_fault (vmf=<optimized out>) at mm/memory.c:4367
#2  __handle_mm_fault (flags=<optimized out>, address=<optimized out>, vma=<optimized out>) at mm/memory.c:4504
#3  handle_mm_fault (vma=<optimized out>, address=12040240, flags=<optimized out>, regs=<optimized out>) at mm/memory.c:4602
#4  0xffffffff8114b2a4 in do_user_addr_fault (regs=0xffff8880045fff58, hw_error_code=6, address=12040240) at arch/x86/mm/fault.c:1372
#5  0xffffffff824e4c09 in handle_page_fault (address=<optimized out>, error_code=<optimized out>, regs=<optimized out>) at arch/x86/mm/fault.c:1429
#6  exc_page_fault (regs=0xffff8880045fff58, error_code=6) at arch/x86/mm/fault.c:1482
#7  0xffffffff82600ace in asm_exc_page_fault () at ./arch/x86/include/asm/idtentry.h:538

我们知道缺页中断本质上也是一个缺页异常,cpu处理这种异常会分发到特定的异常处理函数,比如这里调用到exc_page_fault,最终就会调用进入do_anonymous_page匿名缺页中断。

匿名缺页中断

pte不存在的情况下,如果vma_is_anonymous返回true判定是匿名页:

static inline bool vma_is_anonymous(struct vm_area_struct *vma)                                                                                                          
{
    return !vma->vm_ops;
}

即设置了vma->vm_ops就不是匿名页,vm_ops又是哪里设置的呢? 向上看mmap_region中有call_mmap调用,最终会调用到ext4中具体的mmap函数设置:

 OK,经过上面判定最终确认是匿名缺页(比如mmap函数使用的时候指定了file 映射设置vm_ops,自然不会进入匿名缺页逻辑)。具体匿名缺页函数可以参照如下文章:

Linux 匿名页的生命周期_nginux的博客-CSDN博客

文件缺页中断

如果上面逻辑没有进入匿名缺页,自然进入文件缺页的处理流程,即do_fault函数,文件缺页根据mmap中的flag又多为多种逻辑:

 FAULT_FLAG_WRITE根据cpu状态而设置的一个flag,没有置位说明是只读异常,那么调用do_read_fault;否则意味是写异常,又要细分是否为写时复制,如果vm_flags没有设置VM_SHARED意味PRIVATE,调用do_cow_fault触发写时复制,否则为do_share_fault共享。

根据前面分析vm_flags就来自于mmap函数的flag,对这里的写异常,如果设置了MAP_SHARED,那么这里就进入了do_shared_fault,否则是do_cow_fault。

根据mmap使用MAP_SHARED的文件映射,写时缺页会把内容也会写回磁盘,所以我们推测do_shared_fault内部会进行文件回写逻辑:

 fault_dirty_shared_page来实现这部分逻辑。

do_wp_page

留个坑后面补上

父子进程写时复制的场景

学过操作系统都知道,linux为了性能考虑,fork系统调用子进程并不会完全复制父进程的物理page,两者共享物理内存,同时也比较省内存。只有等任何一方写数据的时候才会触发COW。我们思考如下问题:

如果父进程执行如下流程:

1. addr = mmap(PROT_READ|PROT_WRITE, MAP_PRIVATE)先创建了一个虚拟地址的映射

2. 向addr 写入了数据.

3.fork一个子进程.

4.子进程向addr写入数据触发COW。

理论推导第四步应该会走do_wp_page逻辑,但是要走入整个逻辑要满足如下条件:

 就是说entry页表项必须是不可写的,我们知道我们mmap的时候明明是设置了PROT_READ | PROT_WRITE明明是可读写,那么第一次缺页创建pte的时候pte也是可读写的,那么到底是哪里将pte修改成只读的?答案:fork系统调用发现是private的私有映射,就会将相应的pte修改成只读。

 

参考文章:

Linux内核虚拟内存管理之匿名映射缺页异常分析_vm_get_page_prot_零声教育的博客-CSDN博客

详细讲解Linux内核写时复制技术COW机制(手撕源代码) - 知乎

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

Linux mmap系统调用视角看缺页中断 的相关文章

  • 使用 inotify 的正确方法是什么?

    我想使用inotifyLinux 上的机制 我希望我的应用程序知道文件何时aaa被改变了 您能给我提供一个如何做到这一点的示例吗 文档 来自监视文件系统活动 inotify https developer ibm com tutorials
  • 配置:错误:无法运行C编译的程序

    我正在尝试使用 Debian Wheezy 操作系统在我的 Raspberry Pi 上安装不同的软件 当我运行尝试配置软件时 我尝试安装我得到此输出 checking for C compiler default output file
  • 如何访问 mmaped /dev/mem 而不导致 Linux 内核崩溃?

    我有一个简单的程序 尝试访问用户空间中的物理内存 其中内核存储第一个结构页 在 64 位机器上 该地址是 内核虚拟地址 ffffea0000000000 物理地址 0000620000000000 我正在尝试通过用户空间中的 mmap 访问
  • C - 为什么我无法映射较小(256UL 或更小)的内存?

    请告诉我 为什么我的简单应用程序无法映射较小的内存 而且 为什么有这样一个特定的边界 257UL define MAP SIZE 256UL or below fail define MAP SIZE 257UL ok include
  • 从c调用汇编函数

    我试图从 c 调用汇编函数 但我不断收到错误 text globl integrate type integrate function integrate push ebp mov esp ebp mov 0 edi start loop
  • Linux“屏幕”的 Windows 等效项还是其他替代方案?

    我正在寻找一种在 Windows 环境中控制程序的方法 我希望它与 Linux 软件有点相似 screen 我搜索的原因是我需要使用标识符启动一个程序 在 Windows 上 这样我以后就能够关闭该特定程序 而无需关闭其他任何程序 即使实际
  • 错误:命令“c++”失败,退出状态为 1

    所以我尝试按照以下说明安装 Pyv8https andrewwilkinson wordpress com 2012 01 23 integrating python and javascript with pyv8 https andre
  • 如何在 Linux 中重新添加 unicode 字节顺序标记?

    我有一个相当大的 SQL 文件 它以 FFFE 的字节顺序标记开头 我使用 unicode 感知的 linux 分割工具将此文件分割成 100 000 行块 但是当将这些传递回窗口时 它确实not与第一个部分以外的任何部分一样 只是它具有
  • 在 Docker 容器中以主机用户身份运行

    在我的团队中 我们在进行开发时使用 Docker 容器在本地运行我们的网站应用程序 假设我正在开发 Flask 应用程序app py具有依赖关系requirements txt 工作流程大致如下 I am robin and I am in
  • XAMPP Windows 上的 Php Cron 作业

    嗯 我是这个词的新手CRON 据我所知 这是一个Unix安排特定操作在定义的时间间隔后执行的概念 我需要运行一个php文件 每小时更新一次数据库 但我的困惑在于安排执行 我在用XAMPP用于 Windows 7 上的本地开发测试 我发现了什
  • 使用 ProcessBuilder 运行 shell 脚本

    我正在尝试使用 Java 和 ProcessBuilder 运行脚本 当我尝试运行时 我收到以下消息 error 2 没有这样的文件或目录 我不知道我做错了什么 但这是我的代码 ps 我尝试只执行不带参数的脚本 错误是相同的 String
  • 计算 TCP 重传次数

    我想知道在LINUX中是否有一种方法可以计算一个流中发生的TCP重传的次数 无论是在客户端还是服务器端 好像netstat s解决了我的目的
  • Python将文件从Linux复制到WIndows

    我正在构建一个网站 该网站有一个表单 可以捕获用户数据并在用户数据上运行一些cgi cgi 的第一步是需要将文件从 Linux Web 服务器复制到 Windows 计算机 服务器将使用 Active Directory 角色帐户作为复制凭
  • 为什么docker容器提示“权限被拒绝”?

    我使用以下命令来运行 docker 容器 并从主机映射目录 root database 到容器 tmp install database docker run it name oracle install v root database t
  • 可以作为命令行参数传递多少数据?

    在 Linux 下生成进程时可以发送多少字节作为命令行参数 gahooa 推荐了一篇好文章http www in ulm de mascheck various argmax http www in ulm de mascheck vari
  • 在非实时操作系统/内核上执行接近实时任务的最佳方法是什么?

    在一台 GNU Linux 机器上 如果想要执行 实时 亚毫秒级时间关键 任务 您几乎总是必须经历漫长 复杂且容易出现问题的内核补丁过程 以提供足够的支持 1 http en wikipedia org wiki RTLinux Backg
  • 用于时间线数据的类似 gnuplot 的程序

    我正在寻找一个类似 gnuplot用于在时间轴中绘制数据图表的程序 类似 gnuplot 在 Linux 上运行 命令行功能 GUI 对我帮助不大 可编写脚本的语法 输出为 jpg png svg 或 gif 输出应该是这样的 set5 s
  • 如何在linux中使用iptables将http和https流量转发到透明代理[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 这个问题似乎不是关于主要由程序员使用的特定编程问题 软件算法或软件工具 help on topic 如果您认为该问题与主题相关另一个 St
  • 如何使用 go1.6.2 构建 linux 32 位

    有没有任何组合GOARCH and GOOS我可以设置哪些值来构建 ELF 32 位二进制文 件 GOOS linux and GOARCH 386 更多示例 架构 32 bit gt GOARCH 386 64 bit gt GOARCH
  • 如何回忆上一个 bash 命令的参数?

    Bash 有没有办法回忆上一个命令的参数 我通常这样做vi file c其次是gcc file c Bash 有没有办法回忆上一个命令的参数 您可以使用 or 调用上一个命令的最后一个参数 Also Alt can be used to r

随机推荐

  • 什么是即时通讯?即时通讯的发展

    一 即时通讯是什么 即时通讯是通过技术来体现在线聊天 交流的软件 有两种架构 一种是C S架构 采用客户端 服务器形式 用户使用过程中需要下载安装客户端软件 比如 微信 QQ 陌陌 钉钉 企业微信 飞书等等通讯软件 采用B S架构 浏览器
  • 小智AI ChatGPT的优点和局限性:

    自然度高 ChatGPT能够生成非常自然的语言 让用户感觉像是在和一个真实的人进行交流 多功能性 ChatGPT可以用于很多不同的场景 比如智能客服 聊天机器人 文本生成 语音合成等等 知识储备 ChatGPT在其训练过程中已经接触到了大量
  • 1024程序员节,庆祝上海csdn嘉年华的圆满结束,也庆祝CDC的诞生,也很开心看到理智偶像三太子傲丙

    前言 1024程序员节 庆祝10月23号 上海csdn嘉年华的圆满结束 也庆祝CDC的诞生 也很开心看到理智偶像三太子傲丙 哦耶 1 现场签到 2 很幸运能拿到csdn的嘉宾证 并参与这次嘉年华活动 3 收到了官方给我们的小礼物 很开心 也
  • 无显卡也能AI作画

    经典碎碎念 事情起因是这样的 我之前写了如何在linux上用Stable Diffusion WebUI 里边提到我迟迟没有弄webui是因为我笔记本A卡 台式机显卡带不动 所以无奈只能使用学校服务器搭一个 当时有人说我 你自己电脑不行怎么
  • 基于GEE平台的植被覆盖度(FVC)像元二分法计算

    一 植被覆盖度计算方法 植被覆盖度FVC Fractional Vegetation Cover 定义为单位面积内绿色植被冠层垂直投影面积所占比例 FVC是衡量地表植被状况的重要指标之一 也是区域生态系统环境变化的重要指示 对水文 生态 区
  • Angular练习之animations动画二

    返回目录 回顾 文章基于angular的练手项目 文章目录前一篇文章 Angular练习之animations动画 介绍了在angular中使用动画的基本方法 引入动画模块 gt 创建动画对象 gt 在动画载体上使用 我觉得其核心的内容在创
  • python datetime.timedelta()函数介绍

    一 timedelta 函数说明 timedelta 表示两个 date 对象或者 time 对象 或者 datetime 对象之间的时间间隔 精确到微秒 class datetime timedelta days 0 seconds 0
  • 最全的Java笔试题库之选择题篇-总共234道【1~60】

    1 下面中哪两个可以在A的子类中使用 class A protected int method1 int a int b return 0 A public int method 1 int a int b return 0 B priva
  • Docker搭建ElasticSearch

    Docker这个容器技术已经非常成熟了 市面上用的公司也特别多 我呢也经常用 也被这Docker经常坑 像什么mysql镜像版本更新后远程无法连接咯 什么虚拟机或者虚拟ip使用Docker搭建Nginx外部无法访问咯 再像这个ES启动报错
  • import { resolveComponent as _resolveComponent, createVNode as _createVNode, createTextVNode as _cr

    import resolveComponent as resolveComponent createVNode as createVNode createTextVNode as createTextVNode withCtx as wit
  • 高频golang面试题:简单聊聊内存逃逸?

    文章目录 问题 怎么答 举例 问题 知道golang的内存逃逸吗 什么情况下会发生内存逃逸 怎么答 golang程序变量会携带有一组校验数据 用来证明它的整个生命周期是否在运行时完全可知 如果变量通过了这些校验 它就可以在栈上分配 否则就说
  • 乐划锁屏推出“屏上看展”,用创意“解锁”艺术新体验

    在移动互联网时代 手机不仅是重要的通讯工具 作为点亮屏幕后的 第一眼 手机锁屏也为人们提供了更加集成 更加多元的信息接收渠道 为了满足人们的碎片化消遣需求 加速信息传播 OPPO依托锁屏点亮即触达的特点 将锁屏壁纸作为探索碎片化娱乐的新通道
  • Exception encountered during context initialization - cancelling refresh attempt: org.springframewor

    Exception encountered during context initialization cancelling refresh attempt org springframework beans factory BeanCre
  • Android通过DownloadManager实现App的版本更新功能

    1 DownloadManager介绍 DownloadManger是android 2 3 api level 9 开始 提供的用于优化处理长时间的下载操作 DownloadManager 处理Http Https连接并监控连接中的状态变
  • 如何使用Python爬虫抓取数据?

    Python爬虫应用十分广泛 无论是各类搜索引擎 还是日常数据采集 都需要爬虫的参与 其实爬虫的基本原理很简单 今天小编就教大家如何使用Python爬虫抓取数据 感兴趣的小伙伴赶紧看下去吧 工具安装 首先需要安装Python的request
  • sqli-labs第十八关~第二十二关

    这几关均为请求头注入 请求头记录的信息可以拼接到SQL语句上 User Agent 浏览器身份标识字符串 Referer 表示浏览器访问的前一个页面 可以认为是之前访问页面的连接件浏览器带到了当前页面 Accept 可接受的响应内容类型 C
  • 攻防世界-re-for-50-plz-50

    1 下载附件 exeinfo查壳 无壳 2 32位IDA分析 主函数分析 在注释里 31的来源 python和C语言 a cbtcqLUBChERV Nh X D X YPV CJ print len a include
  • Shell条件判断的三种方式

    一 三种方式 1 test 条件表达式 2 条件表达式 3 条件表达式 支持正则 注意 和 括号左右两边需要留空格 二 常用判断条件 e 判断文件是否存在 任何类型文件 e app echo f 判断文件是否存在并且是一个普通文件 f st
  • selenium学习网址

    1 http www testclass net selenium java testclass网址 2 http www yiibai com selenium selenium ide html yiibai网址 转载于 https w
  • Linux mmap系统调用视角看缺页中断

    问题 1 mmap具体是怎么实现比read write少一次内存copy的 2 mmap共享映射和私有映射在内核实现的时候到底有什么区别 3 mmap的文件映射和匿名映射在内核实现的时候到底有什么区别 4 父子进程的COW具体怎么实现的 概