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

linux-内核锁 目录: 一、铺垫知识 1、指令执行流 2、上下文 3、抢占 二、内核锁基础知识 1、为什么要用锁?why 2、锁保护什么?what 3、锁是如何保护资源的?How 三、各类锁的介绍 1、原子操作 2、spinlock 3、mutex 4、… 进程指令执行流 代码在CPU上执行的指令数据流,由一系列代码组成。可分为两大类:线程维度和中断维度 1、cpu只要上电,就需要不停的执行指令,永不停歇,若无事可做,那就执行空指令,直到下电。cpu类似一个跑道,各个task轮流到跑 阅读详情
问题

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的博客-优快云博客

文件缺页中断

如果上面逻辑没有进入匿名缺页,自然进入文件缺页的处理流程,即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_零声教育的博客-优快云博客

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

Linux mmap读/写触发共享文件页生命周期 Linux的mm内存子系统的核心功能就要要管理各种类型的page,确保能高效分配和释放,让物理内存得以最大化使用。初识内存系统往往关注的是page的申请和管理流程,容易忽略page的释放回收流程,其实理解mm中的内存回收和释放也是最核心的机制。 阅读详情

相关推荐

Linux内存管理子系统——mmap内存映射原理分析(dax文件系统的mmap)

Linux mmap分析 内核版本:linux-5.16 1. 虚拟内存概要内容简介 1.1. mm_struct 和 vm_area_struct // mm_struct 和 vm_area_struct 的简要成员 struct mm_struct { unsigned long start_brk, brk, start_stack; } __attribute__((preserve_access_index)); struct vm_area_struct { unsigned lo

Imagine Miracle的博客 3754

LWN:采用 per-VMA锁进行并发page-fault处理!

并发page-fault处理

m0_51717456的博客 783

Linux 内存管理揭秘:从虚拟地址到物理页帧的映射之旅

当 CPU 访问一个虚拟地址,而对应的页表项 P 位(Present)为 0 时,MMU 触发缺页中断(Page Fault),将控制权交给内核的缺页处理程序。按需加载(Demand Paging):程序启动时不加载全部代码/数据,仅在访问时加载;内存映射文件(mmap):文件内容按需从磁盘读入内存;写时复制(COW):fork 后共享页,首次写入时才复制;交换(Swapping):将不活跃的页换出到磁盘,腾出物理内存。Linux 内存管理是一个从硬件到软件、从虚拟到物理的精密系统。虚拟地址空间。

从事移动开发八年,csdn博客专家,阿里云特邀专家,华为云云享专家,高级网络信息安全工程师,大数据工程师(高级),python技术开发(高级),HarmonyOS 应用开发者高级认证,现在某学校任教。 15

有关与进程间通信的mmap方法以及进程间互斥锁的使用

这是一篇在面试,遇到的问题,之前只接触过线程的互斥锁,但是面试可能会问到所以写了这篇文章。

wlqxyl的博客 1350

解决redhat8/centos8无法使用yum问题(报错:This system is not registered to Red Hat Subscription Management)

解决redhat无法使用yum问题、以及替换repo文件后仍无法使用yum的问题

qq_43569119的博客 4342

JQ8900语音播报模块在RT-Thread系统下的驱动移植与测试详解

本文详细讲解了如何在RT-Thread嵌入式操作系统中,为JQ8900语音播报模块进行驱动移植与功能测试。内容涵盖从获取驱动代码、配置Kconfig工程、编译烧录到核心代码解析的完整流程,并提供了基于串口通信的上电测试与问题排查方法,帮助开发者快速掌握在RT-Thread系统下集成外部模块的核心技能。

weixin_35677363的博客 593

LWN:修正per-VMA locking的问题!

关注了就能看到更多这么棒的文章哦~Stabilizing per-VMA lockingBy Jonathan CorbetJuly 13, 2023ChatGPT assisted translationhttps://lwn.net/Articles/937943/内核开发过程经常会合入一些对最基本的子系统的大规模更改,并仍然能够每九到十周就发布一次稳定版本。但偶尔会出现开发社区不想看到的情况...

Linux News搬运工 1535

WPF+Prism+LiveCharts+materialdesignin 搭建WPF开发框架

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。提示:以下是本篇文章正文内容。

T_Tboy的博客 3050

Linux内存管理三层次解密

摘要:Linux内存管理系统采用分层架构,包含用户空间层(提供malloc等系统调用接口)、内核空间层(处理VMA管理、缺页中断、页面回收等核心功能)和硬件层(MMU、TLB及物理内存)。该系统通过系统调用连接用户层与内核层,实现了从应用到底层硬件的完整内存管理机制。各层协同工作,构建了复杂而高效的内存管理体系。

Jia ming 的日常学习笔记 458

VCS HVP与验证计划planner:数字IC验证环境搭建与收敛实践

在数字IC验证中,VCS 是广泛使用的编译型仿真器,HVP 通常指面向硬件验证平台的高性能编译选项集,用于开启 SystemVerilog 类、随机约束和 NTB 等能力;planner 则指验证计划管理,核心是把功能点与测试用例、覆盖点建立映射。理解 VCS 先编译后仿真的原理,有助于优化增量编译、调试访问和覆盖率采集,提升回归收敛效率。规划驱动让激励不再散落,设计改版时能快速定位受影响用例,交接和覆盖率收敛更有依据。无论是 UVM 环境搭建、编译参数选择,还是验证计划表维护,都需要把工具选项与规划方法结

weixin_42543046的博客 336

RT-DETR改进策略【卷积层】| CVPR-2020 Strip Pooling 空间池化模块 处理不规则形状的对象 含二次创新

一、本文介绍 本文记录的是利用Strip Pooling模块优化RT-DETR的目标检测网络模型。Strip Pooling结合了长而窄的卷积核形状在一个空间维度上的长程关系捕捉能力和在另一个空间维度上的局部细节捕捉能力,有效地处理复杂的场景信息。这一机制通过采用1×N1×N1×N或N×1N×1N×1的池化核形状来适应不同的图像特征,提高模型对目标形状和分布的适应性。在场景解析网络中,Strip Pooling可以被用于提升对具有长程带状结构或离散分布目标的解析能力,特别是在复杂场景或不同对象布局条件下效果

Limiiiing的博客 580

从 Linux 内核角度探秘 JDK MappedByteBuffer

在之前的文章中,笔者为大家详细剖析了 JDK Buffer 的整个设计体系,从总体上来讲,JDK NIO 为每一种 Java 基本类型定义了对应的 Buffer 类(boolean 类型除外)。而 Buffer 本质上其实是 JDK 对 OS 中某一段内存在 Java 语言层面上的封装,当然了,这里的内存指的是虚拟内存,我们需要从之前文章中的内核空间视角切换到用户空间上来,。JVM 在操作系统的视角来看其实就是一个普通的进程,而进程的虚拟内存空间我们通过前面的洗礼,可以说是非常熟悉了。

dsgdauigfs的博客 1117

C# 上位机之海康工业相机开发(SDK)实战教程

海康工业相机的C#开发核心是基于MVS SDK的“初始化→枚举→连接→采集→释放”流程,其中图像回调处理和格式转换是关键。严格按照SDK文档处理设备类型(网口/USB)和像素格式;及时释放图像资源,避免内存泄漏;错误码是排查问题的重要依据(可参考SDK中的“错误码说明”文档)。掌握这些基础后,可结合机器视觉算法(如OpenCV)实现缺陷检测、尺寸测量等高级功能,构建完整的工业视觉系统。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 3829

缺页中断(Page Fault)详细介绍 + 代码示例

摘要 缺页中断是虚拟内存管理的核心机制,当程序访问未加载到物理内存的虚拟页面时触发。内核处理中断后会加载对应页面并更新页表,对应用层透明。缺页分为有效缺页(正常加载)和无效缺页(非法访问)。其核心特性包括透明性、按需加载和分级处理。实现流程涉及CPU查询页表、内核校验地址、磁盘加载和页表更新。代码示例展示了有效缺页的透明加载、无效缺页导致的段错误以及Linux下的缺页统计观测。该机制突破了物理内存限制,但也存在性能开销和页面置换风险,是虚拟内存系统的基础实现方式。

2301_80136889的博客 1288

【XAI】透视深度学习:CNN与Transformer的可解释性方法

深度学习模型的可解释性方法解析:本文探讨了CNN和Transformer两类主流模型的可解释性技术。针对CNN,介绍了显著性图、类激活图(CAM/Grad-CAM)和基于扰动的方法,通过可视化重要像素区域揭示决策依据。对于Transformer,重点分析了注意力机制可视化及其在文本处理中的应用,并介绍了积分梯度等归因方法。文章包含详细的Python实现示例(使用Captum库),涵盖从MNIST图像显著性分析到BERT文本注意力可视化,为初学者提供了可操作的技术指南。这些方法有助于增强模型透明度,提升AI系

u012133341的博客 381

使用MATLAB实现PAC2002轮胎模型的TIR文件解析和模型计算详解

PAC2002轮胎模型是由荷兰TNO公司开发的一种半经验的轮胎模型,用于描述轮胎在不同工况下的力学特性。该模型基于一系列物理和经验参数,通过复杂的数学表达式来模拟轮胎的力学行为,包括纵向力、侧向力、回正力矩等。

qq_38334677的博客 2428

JVM虚拟延迟内存分配机制源码剖析

本文分析了JVM虚拟内存管理的三阶段机制:预留(Reserved)、提交(Committed)和物理映射。在Linux环境下,JVM通过mmap系统调用预留虚拟地址空间,此时仅在内核创建VMA结构而不分配物理内存。提交阶段通过mprotect修改VMA权限,内核进行Overcommit审计但依然延迟物理内存分配。最终在首次访问内存时触发缺页中断,内核才从伙伴系统分配物理页帧并建立映射。这种延迟分配机制有效提高了内存利用率,同时也解释了JVM内存指标与操作系统实际消耗的差异。

wuminyu的博客 362

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

操作系统内核视角下的静态与动态链接机制深度剖析

本文从操作系统内核视角剖析了程序加载与链接机制。内核通过解析ELF文件程序头表区分静态与动态链接程序:动态链接程序包含PT_INTERP段指定动态链接器路径,而静态链接程序则是自包含的。内核主要负责加载过程,将动态链接器或主程序映射到内存空间,而符号解析等链接操作由用户态工具完成。文章通过readelf工具对比分析了两种链接方式在ELF结构上的差异,并解释了关键概念如VMA、Page Fault等,为理解程序运行机制和性能优化提供了基础。

lcreek的博客 750

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

malloc申请内存一定会引起进程Heap的Rss变化吗?

前言 linux的开发人员,大概都知道可以通过 cat /proc/pid/smaps 来查看进程的memory占用情况,以确定线程占用memory是否过大: 可以看到每个大的字段都有size、Rss、Pss等不同的小的字段,它们可以各自理解为: size:该字段所占用的虚拟内存大小 Rss/Pss:该字段所占用的物理内存大小;两者的区别在于,举例来说,libc-2.17.so被进程A和进程B都加载了,但实际上,这种共享的so所占用的物理内存是一份,而不是占用2份,那么假设libc-2.17.s

lqw198421的专栏 1527

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Linux 下 malloc 内存分配机制详解

在 Linux 系统中,malloc() 是 C 语言标准库(glibc)提供的动态内存分配函数。📌 示例:运行一个多线程程序后查看 /proc//maps,你会看到一个 [heap] 区域和多个匿名 mmap 区域——它们分别对应 main arena 和 thread arenas。因此,一个进程可以有多个 arena,每个 arena 都是一个独立的“堆”,拥有自己的空闲块管理结构和锁。Arena 是 malloc 用来管理内存的独立分配区,目的是支持高效、线程安全的内存分配。

唐装鼠的主页 1043

Linux文件系统:从用户态API到内核实现的深度解析

文件系统作为操作系统核心组件,通过虚拟文件系统(VFS)层实现用户态与内核态的交互。其核心原理是将磁盘、设备等统一抽象为文件描述符,通过系统调用桥接用户空间请求与底层存储操作。在性能优化层面,Page Cache机制通过内存缓存减少磁盘I/O,而O_DIRECT和mmap等技术则提供了绕过缓存的直接访问方案。理解文件描述符与inode的映射关系、掌握vfs_read/vfs_write等内核函数调用链,对于开发数据库、分布式存储等高性能系统至关重要。通过strace、perf等工具可观测实际文件操作路径,本

weixin_30530939的博客 354

知识体系之APUE/内核编程

网络编程

JaweG 6975

Rocket MQ : 拒绝神化零拷贝

内存加持,充分发挥硬件能力文件预热,将中断响应提前到初始化阶段mlock禁止Linux交换内存madvise向操作系统提出内存空间的操作建议或者指示优秀的文件系统设计,尽最大可能保证顺序写将磁盘上的物理文件直接映射到用户态的内存地址中(这种Mmap的方式减少了传统IO将磁盘文件数据在操作系统内核地址空间的缓冲区和用户应用程序地址空间的缓冲区之间来回进行拷贝的性能开销)

mxt51220的博客 559

深入理解 JVM 与 Linux 内存:区域划分、分配机制与交互全过程

JVM 运行时数据区严格遵循《Java 虚拟机规范》,同时在 HotSpot + Linux 环境下有具体实现差异,并非所有内存区域都受 JVM 自身管控。权责划分:JVM 管“用户空间的内存划分与堆内回收”,Linux 管“底层物理内存分配、Swap 调度、内核内存管理”,二者分工明确,缺一不可。关键认知:-Xmx 只是 Java 堆的上限,JVM 进程总内存 = Java 堆 + 线程栈 + Metaspace + 直接内存 + 其他开销,因此 RES 必然大于 -Xmx,这是正常现象。

2303_79278759的博客 507

Linux中的虚拟内存机制及其应用

  最近学习了Linux中的虚拟内存,这个机制真的是非常的妙。虚拟内存可以说是硬件异常、主存、外存和操作系统的完美交互,而且更妙的是,这个机制是完全自动运行的。如果我们理解一点点虚拟内存的原理,就可以理解经常出现的内存错误的原因,还可以理解什么是内存映射mmap。 一、物理地址空间是什么   理解虚拟地址空间还得从物理地址空间开始说起。我们知道内存就像一个数组,每个存储单元被分配了一个地址,这个地...

xstarP的博客 380

17.揭秘虚拟地址空间:进程内存管理的核心

本文深入探讨了Linux系统中的虚拟地址空间机制及其实现原理。主要内容包括:1)32位系统中4GB虚拟地址空间的划分(用户空间与内核空间);2)页表在虚拟地址到物理地址转换中的作用;3)进程创建时的写时拷贝机制;4)mm_struct和vm_area_struct对虚拟地址空间的管理方式;5)虚拟地址空间的三大优势:内存隔离保护、降低耦合度、简化内存管理;6)缺页中断机制实现动态加载。文章通过实例分析解释了父子进程变量修改、野指针访问等问题,并阐述了进程挂起时内存管理的实现细节。

keyipatience的博客 457
上一篇: Linux 源码剖析匿名页的生命周期
下一篇: Linux源码剖析匿名共享内存shmem原理
OS技术解密
博客等级 码龄16年 3760粉丝 189原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值