linux内存管理深入分析

深入理解Linux内存管理 内存是计算机最重要的资源之一,内存管理是操作系统最重要的任务之一。内存管理并不是简单地管理一下内存而已,它还直接影响着操作系统的风格以及用户空间编程的模式。可以说内存管理的方式是一个系统刻入DNA的秉性。既然内存管理那么重要,那么今天我们就来全面系统地讲一讲Linux内存管理。外存是程序存储的地方,内存是进程运行的地方。外存相当于是军营,内存相当于是战场。选择一个良好的战场才有利于军队打胜仗,实现一个完善的内存管理机制才能让进程多快好省地运行。如何更好地实现内存管理一直是操作系统发展的一大主题。在此过程中内 阅读详情

内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己来解决(用户空间的内存错误可以抛给内核来解决)。本文讨论的是在内核之中获取内存的办法,在深入研究实际的接口分配之前我们需要理解一下内核是如何实现内存管理的。

1.linux 内存管理涉及的概念

1.1 页

内核把页作为内存管理的基本单位,内存管理单元(MMU)通常以页为单位进行处理。从虚拟内存的角度看,页就是最小单位。

 内核中用struct page结构表示系统中每个物理页,页的结构体头文件是: <linux/mm_types.h> 位置:include/linux/mm_types.h

/*
 * 页中包含的成员非常多,还包含了一些联合体
 * 其中有些字段我暂时还不清楚含义,以后再补上。。。
 */
struct page {
    unsigned long flags;    /* 存放页的状态,各种状态参见<linux/page-flags.h> */
    atomic_t _count;        /* 页的引用计数 */
    union {
        atomic_t _mapcount;    /* 已经映射到mms的pte的个数 */
        struct {        /* 用于slab层 */
            u16 inuse;
            u16 objects;
        };
    };
    union {
        struct {
        unsigned long private;        /* 此page作为私有数据时,指向私有数据 */
        struct address_space *mapping;    /* 此page作为页缓存时,指向关联的address_space */
        };
#if USE_SPLIT_PTLOCKS
        spinlock_t ptl;
#endif
        struct kmem_cache *slab;    /* 指向slab层 */
        struct page *first_page;    /* 尾部复合页中的第一个页 */
    };
    union {
        pgoff_t index;        /* Our offset within mapping. */
        void *freelist;        /* SLUB: freelist req. slab lock */
    };
    struct list_head lru;    /* 将页关联起来的链表项 */
#if defined(WANT_PAGE_VIRTUAL)
    void *virtual;            /* 页的虚拟地址 */
#endif /* WANT_PAGE_VIRTUAL */
#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
    unsigned long debug_flags;    /* Use atomic bitops on this */
#endif

#ifdef CONFIG_KMEMCHECK
    /*
     * kmemcheck wants to track the status of each byte in a page; this
     * is a pointer to such a status block. NULL if not tracked.
     */
    void *shadow;
#endif
};

物理内存的每个页都有一个对应的 page 结构,看似会在管理上浪费很多内存,其实细细算来并没有多少。比如上面的page结构体,每个字段都算4个字节的话,总共40多个字节。(union结构只算一个字段)那么对于一个页大小 4KB 的 4G内存来说,一个有 4*1024*1024 / 4 = 1048576 个page,一个page 算40个字节,在管理内存上共消耗内存 40MB左右。如果页的大小是 8KB 的话,消耗的内存只有 20MB 左右。相对于 4GB 来说并不算很多。

1.2 区

页是内存管理的最小单元,但是并不是所有的页对于内核都一样。内核将内存按地址的顺序分成了不同的区,有的硬件只能访问有专门的区。内核中分的区定义在头文件 <linux/mmzone.h> 位置:include/linux/mmzone.h内存区的种类参见 enum zone_type 中的定义。内存区的结构体定义也在 <linux/mmzone.h> 中。具体参考其中 struct zone 的定义。

其实一般主要关注的区只有3个:

区

描述

物理内存

ZONE_DMADMA使用的页<16MB
ZONE_NORMAL正常可寻址的页16~896MB
ZONE_HIGHMEM动态映射的页>896MB

 某些硬件只能直接访问内存地址,不支持内存映射,对于这些硬件内核会分配 ZONE_DMA 区的内存。

某些硬件的内存寻址范围很广,比虚拟寻址范围还要大的多,那么就会用到 ZONE_HIGHMEM 区的内存,对于 ZONE_HIGHMEM 区的内存,后面还会讨论。

对于大部分的内存申请,只要用 ZONE_NORMAL 区的内存即可。

2. linux 空间获取内存的方法

内核中提供了多种获取内存的方法,了解各种方法的特点,可以恰当的将其用于合适的场景。

2.1 按页获取 - 最原始的方法,用于底层获取内存的方式

以下分配内存的方法参见:<linux/gfp.h>

方法

描述

alloc_page(gfp_mask)只分配一页,返回指向页结构的指针
alloc_pages(gfp_mask, order)分配 2^order 个页,返回指向第一页页结构的指针
__get_free_page(gfp_mask)只分配一页,返回指向其逻辑地址的指针
__get_free_pages(gfp_mask, order)分配 2^order 个页,返回指向第一页逻辑地址的指针
get_zeroed_page(gfp_mask)只分配一页,让其内容填充为0,返回指向其逻辑地址的指针

 alloc_page方法和 get_free_page 方法的区别在于,一个返回的是内存的物理地址,一个返回内存物理地址映射后的逻辑地址。如果无须直接操作物理页结构体的话,一般使用 get_free_page方法。

相应的释放内存的函数如下:也是在 <linux/gfp.h> 中定义的

extern void __free_pages(struct page *page, unsigned int order);
extern void free_pages(unsigned long addr, unsigned int order);
extern void free_hot_page(struct page *page);

在请求内存时,参数中有个 gfp_mask 标志,这个标志是控制分配内存时必须遵守的一些规则。

gfp_mask 标志有3类:(所有的 GFP 标志都在 <linux/gfp.h> 中定义)

  1. 行为标志 :控制分配内存时,分配器的一些行为
  2. 区标志   :控制内存分配在那个区(ZONE_DMA, ZONE_NORMAL, ZONE_HIGHMEM 之类)
  3. 类型标志 :由上面2种标志组合而成的一些常用的场景

 

行为标志主要有以下几种:

行为标志

描述

__GFP_WAIT分配器可以睡眠
__GFP_HIGH分配器可以访问紧急事件缓冲池
__GFP_IO分配器可以启动磁盘I/O
__GFP_FS分配器可以启动文件系统I/O
__GFP_COLD分配器应该使用高速缓存中快要淘汰出去的页
__GFP_NOWARN分配器将不打印失败警告
__GFP_REPEAT分配器在分配失败时重复进行分配,但是这次分配还存在失败的可能
__GFP_NOFALL分配器将无限的重复进行分配。分配不能失败
__GFP_NORETRY分配器在分配失败时不会重新分配
__GFP_NO_GROW由slab层内部使用
__GFP_COMP添加混合页元数据,在 hugetlb 的代码内部使用

 

区标志主要以下3种:

区标志

描述

__GFP_DMA从 ZONE_DMA 分配
__GFP_DMA32只在 ZONE_DMA32 分配 (注1)
__GFP_HIGHMEM从 ZONE_HIGHMEM 或者 ZONE_NORMAL 分配 (注2)

注1:ZONE_DMA32 和 ZONE_DMA 类似,该区包含的页也可以进行DMA操作。
         唯一不同的地方在于,ZONE_DMA32 区的页只能被32位设备访问。
注2:优先从 ZONE_HIGHMEM 分配,如果 ZONE_HIGHMEM 没有多余的页则从 ZONE_NORMAL 分配。

 

类型标志是编程中最常用的,在使用标志时,应首先看看类型标志中是否有合适的,如果没有,再去自己组合 行为标志和区标志。

类型标志

实际标志

描述

GFP_ATOMIC__GFP_HIGH这个标志用在中断处理程序,下半部,持有自旋锁以及其他不能睡眠的地方
GFP_NOWAIT0与 GFP_ATOMIC 类似,不同之处在于,调用不会退给紧急内存池。
这就增加了内存分配失败的可能性
GFP_NOIO__GFP_WAIT这种分配可以阻塞,但不会启动磁盘I/O。
这个标志在不能引发更多磁盘I/O时能阻塞I/O代码,可能会导致递归
GFP_NOFS(__GFP_WAIT | __GFP_IO)这种分配在必要时可能阻塞,也可能启动磁盘I/O,但不会启动文件系统操作。
这个标志在你不能再启动另一个文件系统的操作时,用在文件系统部分的代码中
GFP_KERNEL(__GFP_WAIT | __GFP_IO | __GFP_FS )这是常规的分配方式,可能会阻塞。这个标志在睡眠安全时用在进程上下文代码中。
为了获得调用者所需的内存,内核会尽力而为。这个标志应当为首选标志
GFP_USER(__GFP_WAIT | __GFP_IO | __GFP_FS )这是常规的分配方式,可能会阻塞。用于为用户空间进程分配内存时
GFP_HIGHUSER(__GFP_WAIT | __GFP_IO | __GFP_FS )|__GFP_HIGHMEM)从 ZONE_HIGHMEM 进行分配,可能会阻塞。用于为用户空间进程分配内存
GFP_DMA__GFP_DMA从 ZONE_DMA 进行分配。需要获取能供DMA使用的内存的设备驱动程序使用这个标志
通常与以上的某个标志组合在一起使用。

 

以上各种类型标志的使用场景总结:

场景

相应标志

进程上下文,可以睡眠使用 GFP_KERNEL
进程上下文,不可以睡眠使用 GFP_ATOMIC,在睡眠之前或之后以 GFP_KERNEL 执行内存分配
中断处理程序使用 GFP_ATOMIC
软中断使用 GFP_ATOMIC
tasklet使用 GFP_ATOMIC
需要用于DMA的内存,可以睡眠使用 (GFP_DMA|GFP_KERNEL)
需要用于DMA的内存,不可以睡眠使用 (GFP_DMA|GFP_ATOMIC),或者在睡眠之前执行内存分配

2.2 按字节获取 - 用的最多的获取方法

这种内存分配方法是平时使用比较多的,主要有2种分配方法:kmalloc()和vmalloc()

kmalloc的定义在 <linux/slab_def.h> 中

/**
 * @size  - 申请分配的字节数
 * @flags - 上面讨论的各种 gfp_mask
 */
static __always_inline void *kmalloc(size_t size, gfp_t flags)
#+end_src

vmalloc的定义在 mm/vmalloc.c 中
#+begin_src C
/**
 * @size - 申请分配的字节数
 */
void *vmalloc(unsigned long size)

kmalloc 和 vmalloc 区别在于:

  • kmalloc 分配的内存物理地址是连续的,虚拟地址也是连续的
  • vmalloc 分配的内存物理地址是不连续的,虚拟地址是连续的

因此在使用中,用的较多的还是 kmalloc,因为kmalloc 的性能较好。因为kmalloc的物理地址和虚拟地址之间的映射比较简单,只需要将物理地址的第一页和虚拟地址的第一页关联起来即可。而vmalloc由于物理地址是不连续的,所以要将物理地址的每一页都和虚拟地址关联起来才行。

 kmalloc 和 vmalloc 所对应的释放内存的方法分别为:

void kfree(const void *)
void vfree(const void *)

2.3 slab层获取 - 效率最高的获取方法

频繁的分配/释放内存必然导致系统性能的下降,所以有必要为频繁分配/释放的对象内心建立缓存。而且,如果能为每个处理器建立专用的高速缓存,还可以避免 SMP锁带来的性能损耗。

 2.3.1 slab层实现原理

linux中的高速缓存是用所谓 slab 层来实现的,slab层即内核中管理高速缓存的机制。

整个slab层的原理如下:

  1. 可以在内存中建立各种对象的高速缓存(比如进程描述相关的结构 task_struct 的高速缓存)
  2. 除了针对特定对象的高速缓存以外,也有通用对象的高速缓存
  3. 每个高速缓存中包含多个 slab,slab用于管理缓存的对象
  4. slab中包含多个缓存的对象,物理上由一页或多个连续的页组成

 高速缓存->slab->缓存对象之间的关系如下图:

mem_cache

 2.3.2 slab层的应用

slab结构体的定义参见:mm/slab.c

struct slab {
    struct list_head list;   /* 存放缓存对象,这个链表有 满,部分满,空 3种状态  */
    unsigned long colouroff; /* slab 着色的偏移量 */
    void *s_mem;             /* 在 slab 中的第一个对象 */
    unsigned int inuse;         /* slab 中已分配的对象数 */
    kmem_bufctl_t free;      /* 第一个空闲对象(如果有的话) */
    unsigned short nodeid;   /* 应该是在 NUMA 环境下使用 */
};

 slab层的应用主要有四个方法:

  • 高速缓存的创建
  • 从高速缓存中分配对象
  • 向高速缓存释放对象
  • 高速缓存的销毁
/**
 * 创建高速缓存
 * 参见文件: mm/slab.c
 * 这个函数的注释很详细,这里就不多说了。
 */
struct kmem_cache *
kmem_cache_create (const char *name, size_t size, size_t align,
    unsigned long flags, void (*ctor)(void *))

/**
 * 从高速缓存中分配对象也很简单
 * 函数参见文件:mm/slab.c
 * @cachep - 指向高速缓存指针
 * @flags  - 之前讨论的 gfp_mask 标志,只有在高速缓存中所有slab都没有空闲对象时,
 *           需要申请新的空间时,这个标志才会起作用。
 *
 * 分配成功时,返回指向对象的指针
 */
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)

/**
 * 向高速缓存释放对象
 * @cachep - 指向高速缓存指针
 * @objp   - 要释放的对象的指针
 */
void kmem_cache_free(struct kmem_cache *cachep, void *objp)

/**
 * 销毁高速缓存
 * @cachep - 指向高速缓存指针 
 */
void kmem_cache_destroy(struct kmem_cache *cachep)

 3. 获取高端内存

高端内存就是之前提到的 ZONE_HIGHMEM 区的内存。

在x86体系结构中,这个区的内存不能映射到内核地址空间上,也就是没有逻辑地址,

为了使用 ZONE_HIGHMEM 区的内存,内核提供了永久映射和临时映射2种手段:

 3.1 永久映射

永久映射的函数是可以睡眠的,所以只能用在进程上下文中。

/* 将 ZONE_HIGHMEM 区的一个page永久的映射到内核地址空间
 * 返回值即为这个page对应的逻辑地址
 */
static inline void *kmap(struct page *page)

/* 允许永久映射的数量是有限的,所以不需要高端内存时,应该及时的解除映射 */
static inline void kunmap(struct page *page)

 3.2 临时映射

临时映射不会阻塞,也禁止了内核抢占,所以可以用在中断上下文和其他不能重新调度的地方。

/**
 * 将 ZONE_HIGHMEM 区的一个page临时映射到内核地址空间
 * 其中的 km_type 表示映射的目的,
 * enum kn_type 的定义参见:<asm/kmap_types.h>
 */
static inline void *kmap_atomic(struct page *page, enum km_type idx)

/* 相应的解除映射是个宏 */
#define kunmap_atomic(addr, idx)    do { pagefault_enable(); } while (0)

以上的函数都在 <linux/highmem.h> 中定义的。

 4. 内核内存的分配方式

内核的内存分配和用户空间的内存分配相比有着更多的限制条件,同时也有着更高的性能要求。

下面讨论2个和用户空间不同的内存分配方式。

 4.1 内核栈上的静态分配

用户空间中一般不用担心栈上的内存不足,也不用担心内存的管理问题(比如内存越界之类的),

即使出了异常也有内核来保证系统的正常运行。而在内核空间则完全不一样,不仅栈空间有限,而且为了管理的效率和尽量减少问题的发生,内核栈一般都是小而且固定的。 在x86体系结构中,内核栈的大小一般就是1页或2页,即 4KB ~ 8KB,内核栈可以在编译内核时通过配置选项将内核栈配置为1页,配置为1页的好处是分配时比较简单,只有一页,不存在内存碎片的情况,因为一页是本就是分配的最小单位。当有中断发生时,如果共享内核栈,中断程序和被中断程序共享一个内核栈会可能导致空间不足,于是,每个进程除了有个内核栈之外,还有一个中断栈,中断栈一般也就1页大小。

 查看当前系统内核栈大小的方法:

[xxxxx@localhost ~]$ ulimit -a | grep 'stack'
stack size              (kbytes, -s) 8192

 4.2 按CPU分配

与单CPU环境不同,SMP环境下的并行是真正的并行。单CPU环境是宏观并行,微观串行。

真正并行时,会有更多的并发问题。

 

假定有如下场景:

void* p;

if (p == NULL)
{
/* 对 P 进行相应的操作,最终 P 不是NULL了 */
}
else
{
/* P 不是NULL,继续对 P 进行相应的操作 */
}

在上述场景下,可能会有以下的执行流程:

  1. 刚开始 p == NULL
  2. 线程A 执行到 [if (p == NULL)] ,刚进入 if 内的代码时被线程B 抢占
      由于线程A 还没有执行 if 内的代码,所以 p 仍然是 NULL
  3. 线程B 抢占到CPU后开始执行,执行到 [if (p == NULL)]时, 发现 p 是 NULL,执行 if 内的代码
  4. 线程B 执行完后,线程A 重新被调度,继续执行 if 的代码
      其实此时由于线程B 已经执行完,p 已经不是 NULL了,线程A 可能会破坏线程B 已经完成的处理,导致数据不一致

 

在单CPU环境下,上述情况无需加锁,只需在 if 处理之前禁止内核抢占,在 else 处理之后恢复内核抢占即可。

而在SMP环境下,上述情况必须加锁,因为禁止内核抢占只能禁止当前CPU的抢占,其他的CPU仍然调度线程B 来抢占线程A 的执行

 SMP环境下加锁过多的话,会严重影响并行的效率,如果是自旋锁的话,还会浪费其他CPU的执行时间。

所以内核中才有了按CPU分配数据的接口。

按CPU分配数据之后,每个CPU自己的数据不会被其他CPU访问,虽然浪费了一点内存,但是会使系统更加的简洁高效。

 4.2.1 按CPU分配的优势

按CPU来分配数据主要有2个优点:

  1. 最直接的效果就是减少了对数据的锁,提高了系统的性能
  2. 由于每个CPU有自己的数据,所以处理器切换时可以大大减少缓存失效的几率 (*注1)

 

注1:如果一个处理器操作某个数据,而这个数据在另一个处理器的缓存中时,那么存放这个数据的那个

处理器必须清理或刷新自己的缓存。持续的缓存失效成为缓存抖动,对系统性能影响很大。

 4.2.2 编译时分配

可以在编译时就定义分配给每个CPU的变量,其分配的接口参见:<linux/percpu-defs.h>

/* 给每个CPU声明一个类型为 type,名称为 name 的变量 */
DECLARE_PER_CPU(type, name)
/* 给每个CPU定义一个类型为 type,名称为 name 的变量 */
DEFINE_PER_CPU(type, name)

注意上面两个宏,一个是声明,一个是定义。

其实也就是 DECLARE_PER_CPU 中多了个 extern 的关键字

 

分配好变量后,就可以在代码中使用这个变量 name 了。

DEFINE_PER_CPU(int, name);      /* 为每个CPU定义一个 int 类型的name变量 */

get_cpu_var(name)++;            /* 当前处理器上的name变量 +1 */
put_cpu_var(name);              /* 完成对name的操作后,激活当前处理器的内核抢占 */

 

通过 get_cpu_var 和 put_cpu_var 的代码,我们可以发现其中有禁止和激活内核抢占的函数。

相关代码在 <linux/percpu.h> 中

#define get_cpu_var(var) (*({                \
    extern int simple_identifier_##var(void);    \
    preempt_disable();/* 这句就是禁止当前处理器上的内核抢占 */    \
    &__get_cpu_var(var); }))
#define put_cpu_var(var) preempt_enable()  /* 这句就是激活当前处理器上的内核抢占 */

 

4.2.3 运行时分配

除了像上面那样静态的给每个CPU分配数据,还可以以指针的方式在运行时给每个CPU分配数据。

动态分配参见:<linux/percpu.h>

/* 给每个处理器分配一个 size 字节大小的对象,对象的偏移量是 align */
extern void *__alloc_percpu(size_t size, size_t align);
/* 释放所有处理器上已分配的变量 __pdata */
extern void free_percpu(void *__pdata);

/* 还有一个宏,是按对象类型 type 来给每个CPU分配数据的,
 * 其实本质上还是调用了 __alloc_percpu 函数 */
#define alloc_percpu(type)    (type *)__alloc_percpu(sizeof(type), \
                               __alignof__(type))

 


  
  
  
  
  
  
深入理解LINUX内存管理学习笔记 引子 为什么要写这个笔记: 1,这本书的中文版翻译了太垃圾,没法阅读。阅读英文原版,可以很好的理解 作者的思路。作此笔记备忘 2,一直以来学习LINUXkernel的知识缺乏系统化,借对这本书的学习,系统化 的学习一下LINUXkernel。 3,自己一直在做一个toosmall,toosimple的单进程,特权模式,64bit保 护模式的称不上OS的OS,已经做完了bootloader,构思kernel的实现的时 候,困惑在内存管理的实现上,阅读这本书,希望能有利于自己的OS的编写。 4,克服惰性,多读书,希望一天能阅读5页,争取半年内阅读完这本原版700 多页的巨著。 不足: 我不可能完全理解LINUX内存管理的精髓,肯定有很多地方理解错误。希望大 家能够指正,以便提高,谢谢。 学习方法: 可能您第一次阅读的时候很多地方都不理解,不用担心。那您可能需要阅读一些 文件系统的知识。 或者阅读全部笔记后,再回头阅读,有些地方您就理解了。 立即下载

相关推荐

深入解析Linux内存管理

深入解析Linux内存管理 pdf

Linux系统头文件 头文件作用

头文件的作用

awildchild1的博客 576

深入解析Linux内存管理ppt

目录:页表管理 内核页表 物理内存 高端内存 地址映射 虚拟内存 地址空间 高速缓存 页框回收 交换机制 缺页异常 共享内存 文件映射 程序执行

一文讲透Linux内存管理

Linux内存管理是指对系统内存的分配、释放、映射、管理、交换、压缩等一系列操作的管理。在Linux中,内存被划分为多个区域,每个区域有不同的作用,包括内核空间、用户空间、缓存、交换分区等。Linux内存管理的目标是最大限度地利用可用内存,同时保证系统的稳定和可靠性。内存管理是计算机系统中负责管理系统内存资源的一种机制,主要包括内存分配、内存释放、内存映射和虚拟内存管理等方面。它是计算机系统中非常重要的一个组成部分,能够有效地提高系统的资源利用率和应用程序的性能。

LinkSLA的博客 1874

C# 进程间 双内存共享 高帧率图像传输

演示了两个进程之间通过 双内存共享 的方式, 来实时处理图像,并以高帧率(40~60FPS)传输的基本示例。 进程间内存共享的优点:高性能、低延迟、资源效率高、简单可靠。 适用场景:实时图像处理、大数据传输、多进程协作、实时监控系统,等等。

qianqiansd 1996

FSMC驱动LCD显示屏学习2

液晶显示器,简称 LCD(Liquid Crystal Display)相对于上一代 CRT 显示器 (阴极射线管显示器),LCD显示器具有功耗低、体积小、承载的信息量大及不伤眼的优点,因而它成为了现在的主流电子显示设备液晶是一种介于固体和液体之间的特殊物质,它是一种有机化合物,常态下呈液态,但是它的分 子排列却和固体晶体一样非常规则,因此取名液晶。

usjjjsj的博客 1696

Linux中内存管理详解

Linux中内存管理 内存管理的主要工作就是对物理内存进行组织,然后对物理内存的分配和回收。但是Linux引入了虚拟地址的概念。 虚拟地址的作用 如果用户进程直接操作物理地址会有以下的坏处: 1、 用户进程可以直接操作内核对应的内存,破坏内核运行。 2、 用户...

RopenYuan的专栏 4814

激光可燃气体传感器DIY指南:从TDLAS原理到STM32实战(附代码)

本文详细介绍了如何DIY激光可燃气体传感器,从TDLAS原理到STM32实战,包括硬件选型、光路搭建、电子系统设计和嵌入式软件开发。通过TDLAS技术实现高灵敏度甲烷检测,适合工业安全和环境监测应用。附有完整代码和实用调试技巧,帮助开发者快速掌握光学气体检测技术。

fanta的博客 440

Linux内存管理深度理解

这种做法的唯一缺点便是内核空间和用户空间均变小了。按照虚拟化的定义,虚拟内存与物理内存的映射关系是非线性的、随机的,但这种随机映射,在访问内存效率上会低一些,由于内核在系统运行周期是一个最高等级的常驻“进程”,并且资源是紧张的,因此内核建立一套自己”特殊“的映射规则,大大增加了软件复杂度,但为了提高效率,软件如何复杂都是有意义的!2、换言之,BSS段和数据段本质上可以不划分,软件层面的优化措施,一来节省文件空间,二来可以统一初始化,提升效率,对于嵌入式系统而言,资源就是成本,成本就是竞争力,是有必要的;

STCNXPARM的博客 1095

当R语言遇见MaxENT:参数优化的艺术与自动化调参实践

本文探讨了R语言与MaxENT在生态位建模中的结合应用,重点介绍了参数优化与自动化调参的实践方法。通过caret与ENMeval工具链,研究人员可以高效处理多物种、多环境变量的大规模分析任务,提升模型性能与工作效率。文章还涵盖了从数据准备到结果可视化的全流程,为生态学家提供了实用的技术指导。

corn8的博客 455

BambuStudio学习笔记:OpenCSG - 实时构造实体几何(CSG)渲染的 OpenGL 方案

**OpenCSG** 是一个基于 **OpenGL** 的 **构造实体几何(CSG)** 实时渲染库,通过 **深度剥离算法** 实现布尔运算(并集、交集、差集)的可视化。其核心目标是简化复杂几何体的交互式建模,适用于 CAD 原型设计、3D 打印预览、教育工具等场景。

zzzkk2009的专栏 929

linux内存管理_深入分析Linux内核源代码6-Linux 内存管理(2)

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你!————零声学院6.3 内存的分配和回收 在内存初始化完成以后,内存中就常驻有内核映像(内核代码和数据)。以后,随着用 户程序的执行和结束,就需要不断地分配和释放物理页面。内核应该为分配一组连续的页面而建立一种稳定、高效的分配策略。为此,必须解决一个比较重要的内存管理问题,即外碎 片问题。频繁地请求和释放不同大小的一组连续页面,必然...

weixin_40001309的博客 217

GPU:NVIDIA GPU的发展历史,nvidia-smi的简介、安装、使用方法之详细攻略

GPU:NVIDIA GPU的发展历史,nvidia-smi的简介、安装、使用方法之详细攻略 目录 NVIDIA GPU的发展历史 nvidia-smi的简介 1、nvidia-smi是nvidia 的系统管理界面解释相关参数含义 2、NVIDIA系统管理接口——v388.73 3、支持产品: nvidia-smi的安装 nvidia-smi的使用方法 1、列出所有可用的 NVIDIA 设备命令 2、nvidia-smi的基础命令用法 NVIDIA GPU的发展历

头部AI社区如有邀博主AI主题演讲请私信—心比天高,仗剑走天涯,保持热爱,奔赴向梦想!低调,专注,谦虚,自律,反思,成长,还算比较正能量的博主,公益免费传播…内心特别想在AI界做出一些可以推进历史进程影响力的技术(兴趣使然,有点小情怀,也有点使命感呀 1万+

深入分析Linux内核源代码6-Linux 内存管理(1)

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你! ————零声学院 存储器是一种必须仔细管理的重要资源。在理想的情况下,每个程序员都喜欢无穷大、 快速并且内容不易变(即掉电后内容不会丢失)的存储器,同时又希望它是廉价的。但不幸 的是,当前技术没有能够提供这样的存储器,因此大部分的计算机都有一个存储器层次结构, 即少量、快速、昂贵、易变的高速缓存(cache);若干兆字节的中等速度、中等价格、易变 的主存储器(RAM);数百兆或数千兆的低速、廉价、不易变的磁盘。如图 6.1 所示,这些资 源.

资料qun832218493 3024

上位机图像处理和嵌入式模块部署(qmacvisual入门)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 虽然我们前面学习了很多的知识点,比如说在windows这边,用qt写界面,用opencv写图像处理代码;在linux这边先用树莓派测试,最后再部署到自己的平台上面。但是,对于一个商业软件是怎么运行的,很多时候我们心理还是没有底,或者说,自己写的软件距离一个商业软件还有多远,大部分学习的同学是不知道的。 就算有的同学说,这个时候可以借鉴一下vision pro,或者是

嵌入式-老费,一个分享专业嵌入式知识的blog 1229

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

_深入分析Linux内核源代码6-Linux 内存管理(2)

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你!————零声学院6.3 内存的分配和回收 在内存初始化完成以后,内存中就常驻有内核映像(内核代码和数据)。以后,随着用 户程序的执行和结束,就需要不断地分配和释放物理页面。内核应该为分配一组连续的页面而建立一种稳定、高效的分配策略。为此,必须解决一个比较重要的内存管理问题,即外碎 片问题。频繁地请求和释放不同大小的一组连续页面,必然...

weixin_39613637的博客 108

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

深入分析Linux内核源代码6-Linux 内存管理(2)

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你! ————零声学院 6.3 内存的分配和回收 在内存初始化完成以后,内存中就常驻有内核映像(内核代码和数据)。以后,随着用 户程序的执行和结束,就需要不断地分配和释放物理页面。内核应该为分配一组连续的页面 而建立一种稳定、高效的分配策略。为此,必须解决一个比较重要的内存管理问题,即外碎 片问题。频繁地请求和释放不同大小的一组连续页面,必然导致在已分配的内存块中分散许 多小块的空闲页面。由此带来的问题是,即使这些小块的空闲页面加起来足以满足所请求

资料qun832218493 569

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

linux代码_深入分析Linux内核源代码6-Linux 内存管理(2)

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你!————零声学院6.3 内存的分配和回收在内存初始化完成以后,内存中就常驻有内核映像(内核代码和数据)。以后,随着用户程序的执行和结束,就需要不断地分配和释放物理页面。内核应该为分配一组连续的页面而建立一种稳定、高效的分配策略。为此,必须解决一个比较重要的内存管理问题,即外碎片问题。频繁地请求和释放不同大小的一组连续页面,必然导致在已...

weixin_39565021的博客 288

epub 深入linux内核架构_深入分析Linux内核源代码6-Linux 内存管理(1)

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你!————零声学院存储器是一种必须仔细管理的重要资源。在理想的情况下,每个程序员都喜欢无穷大、快速并且内容不易变(即掉电后内容不会丢失)的存储器,同时又希望它是廉价的。但不幸的是,当前技术没有能够提供这样的存储器,因此大部分的计算机都有一个存储器层次结构,即少量、快速、昂贵、易变的高速缓存(cache);若干兆字节的中等速度、中等价格、...

weixin_28965731的博客 159

Linux内存管理章节五:Linux物理内存管理的核心:伙伴系统深入分析

Linux物理内存管理的核心:伙伴系统深入分析

深耕嵌入式领用多年, 致力于分享嵌入式领域技术! 786

Linux内存管理深入分析:为何`free`显示内存不足,而实际可用很高

本文深入解析Linux系统中free -g命令显示free为0而available较高的现象。通过概念辨析指出这是Linux内存管理的正常表现,系统会优先利用空闲内存作为磁盘缓存(buff/cache)以提升性能。文章详细剖析了used、buff/cache和available指标的计算逻辑,阐述了懒惰回收机制原理,并提供了完整的内存分析方法论:从宏观确认内存分布、定位缓存大户到深度分析进程内存使用。最后强调判断内存压力的正确标准是available而非free值,并给出专业运维建议,帮助读者掌握Linux

tianyuanwo的专栏 693

epub 深入linux内核架构_深入分析Linux内核源代码6-Linux 内存管理(2)

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你!————零声学院6.3 内存的分配和回收在内存初始化完成以后,内存中就常驻有内核映像(内核代码和数据)。以后,随着用户程序的执行和结束,就需要不断地分配和释放物理页面。内核应该为分配一组连续的页面而建立一种稳定、高效的分配策略。为此,必须解决一个比较重要的内存管理问题,即外碎片问题。频繁地请求和释放不同大小的一组连续页面,必然导致在已...

weixin_36028876的博客 125

linux 查询文件大小大于1g_深入分析Linux内核源代码6-Linux 内存管理(1)

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你!————零声学院存储器是一种必须仔细管理的重要资源。在理想的情况下,每个程序员都喜欢无穷大、快速并且内容不易变(即掉电后内容不会丢失)的存储器,同时又希望它是廉价的。但不幸的是,当前技术没有能够提供这样的存储器,因此大部分的计算机都有一个存储器层次结构,即少量、快速、昂贵、易变的高速缓存(cache);若干兆字节的中等速度、中等价格、...

weixin_39766258的博客 229

请求分页内存管理的模拟 c++代码_深入分析Linux内核源代码6-Linux 内存管理(2)...

每天十五分钟,熟读一个技术点,水滴石穿,一切只为渴望更优秀的你!————零声学院6.3 内存的分配和回收 在内存初始化完成以后,内存中就常驻有内核映像(内核代码和数据)。以后,随着用 户程序的执行和结束,就需要不断地分配和释放物理页面。内核应该为分配一组连续的页面而建立一种稳定、高效的分配策略。为此,必须解决一个比较重要的内存管理问题,即外碎 片问题。频繁地请求和释放不同大小的一组连续页面,必然...

weixin_39607447的博客 136
下一篇: linux内核进程调度
LinuxWorking
博客等级 码龄10年 24粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值