linux页框回收之shrink_node函数源码剖析

[内核内存] [arm64] 内存回收4---shrink_node函数详解 文章目录1 shrink_node函数1.1 shrink_node_memcg1.1.1 get_scan_count函数1.1.2 shrink_list函数1.1.2.1 inactive_list_is_low函数1.1.2.2 shrink_active_list函数1.1.2.3 shrink_inactive_list函数1.1.2.3.1页面回收核心函数shrink_page_list匿名页回收流程文件页回收流程1.2 shrink_slab函数 1 shrink_node函数 shrink 阅读详情
概述 

《Linux内存回收入口_nginux的博客-优快云博客》前文我们概略的描述了几种内存回收入口,我们知道几种回收入口最终都会调用进入shrink_node函数,本文将以Linux 5.9源码来描述shrink_node函数的源码实现。

函数调用流程图

 scan_control数据结构

struct scan_control {
	/* How many pages shrink_list() should reclaim */
	unsigned long nr_to_reclaim;

	/*
	 * Nodemask of nodes allowed by the caller. If NULL, all nodes
	 * are scanned.
	 */
	nodemask_t	*nodemask;

	/*
	 * The memory cgroup that hit its limit and as a result is the
	 * primary target of this reclaim invocation.
	 */
	struct mem_cgroup *target_mem_cgroup;

	/*
	 * Scan pressure balancing between anon and file LRUs
	 */
	unsigned long	anon_cost;
	unsigned long	file_cost;

	/* Can active pages be deactivated as part of reclaim? */
    //是否能从active lru列表进行deactivate的reclaim
#define DEACTIVATE_ANON 1
#define DEACTIVATE_FILE 2
	unsigned int may_deactivate:2;
    //如果是1:代表强制进行deactivate,即同时deactivate file和anon
    //如果是0,按需进行deactivate file或者anon,具体条件见下面shrink_node源码分析
	unsigned int force_deactivate:1;
	unsigned int skipped_deactivate:1;

	/* Writepage batching in laptop mode; RECLAIM_WRITE */
	unsigned int may_writepage:1;

	/* Can mapped pages be reclaimed? */
	unsigned int may_unmap:1;

	/* Can pages be swapped as part of reclaim? */
	unsigned int may_swap:1;

	/*
	 * Cgroups are not reclaimed below their configured memory.low,
	 * unless we threaten to OOM. If any cgroups are skipped due to
	 * memory.low and nothing was reclaimed, go back for memory.low.
	 */
	unsigned int memcg_low_reclaim:1;
	unsigned int memcg_low_skipped:1;

	unsigned int hibernation_mode:1;

	/* One of the zones is ready for compaction */
	unsigned int compaction_ready:1;

	/* There is easily reclaimable cold cache in the current node */
    //设置为1代表只回收file page cache,不回收aone page
	unsigned int cache_trim_mode:1;

	/* The file pages on the current node are dangerously low */
    //设置1代表只回收aone page,不回收file page
	unsigned int file_is_tiny:1;

	/* Allocation order */
	s8 order;

	/* Scan (total_size >> priority) pages at once */
	s8 priority;

	/* The highest zone to isolate pages for reclaim from */
	s8 reclaim_idx;

	/* This context's GFP mask */
	gfp_t gfp_mask;

	/* Incremented by the number of inactive pages that were scanned */
	unsigned long nr_scanned;

	/* Number of pages freed so far during a call to shrink_zones() */
	unsigned long nr_reclaimed;

	struct {
		unsigned int dirty;
		unsigned int unqueued_dirty;
		unsigned int congested;
		unsigned int writeback;
		unsigned int immediate;
		unsigned int file_taken;
		unsigned int taken;
	} nr;

	/* for recording the reclaimed slab by now */
	struct reclaim_state reclaim_state;
};
shrink_node函数

static void shrink_node(pg_data_t *pgdat, struct scan_control *sc)
{
	struct reclaim_state *reclaim_state = current->reclaim_state;
	unsigned long nr_reclaimed, nr_scanned;
	struct lruvec *target_lruvec;
	bool reclaimable = false;
	unsigned long file;

	target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat);

again:
	memset(&sc->nr, 0, sizeof(sc->nr));

	nr_reclaimed = sc->nr_reclaimed;
	nr_scanned = sc->nr_scanned;

	/*
	 * Determine the scan balance between anon and file LRUs.
	 */
	spin_lock_irq(&pgdat->lru_lock);
	sc->anon_cost = target_lruvec->anon_cost;
	sc->file_cost = target_lruvec->file_cost;
	spin_unlock_irq(&pgdat->lru_lock);

	/*
	 * Target desirable inactive:active list ratios for the anon
	 * and file LRU lists.
	 */
	if (!sc->force_deactivate) {
		unsigned long refaults;

		refaults = lruvec_page_state(target_lruvec,
				WORKINGSET_ACTIVATE_ANON);
        //anon的refaults值比上次回收发生了变化,或者inactive anon很少,设置
        //DEACTIVATE_ANON表示需要deactivate anon
		if (refaults != target_lruvec->refaults[0] ||
			inactive_is_low(target_lruvec, LRU_INACTIVE_ANON))
			sc->may_deactivate |= DEACTIVATE_ANON;
		else
			sc->may_deactivate &= ~DEACTIVATE_ANON;

		/*
		 * When refaults are being observed, it means a new
		 * workingset is being established. Deactivate to get
		 * rid of any stale active pages quickly.
		 */
		refaults = lruvec_page_state(target_lruvec,
				WORKINGSET_ACTIVATE_FILE);
		if (refaults != target_lruvec->refaults[1] ||
		    inactive_is_low(target_lruvec, LRU_INACTIVE_FILE))
			sc->may_deactivate |= DEACTIVATE_FILE;
		else
			sc->may_deactivate &= ~DEACTIVATE_FILE;
	} else
		sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE;

	/*
	 * If we have plenty of inactive file pages that aren't
	 * thrashing, try to reclaim those first before touching
	 * anonymous pages.
	 */
    //file是inactive file的数量
	file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE);
	if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE))
        //只回收file page,影响get_scan_count
		sc->cache_trim_mode = 1;
	else
		sc->cache_trim_mode = 0;

	/*
	 * Prevent the reclaimer from falling into the cache trap: as
	 * cache pages start out inactive, every cache fault will tip
	 * the scan balance towards the file LRU.  And as the file LRU
	 * shrinks, so does the window for rotation from references.
	 * This means we have a runaway feedback loop where a tiny
	 * thrashing file LRU becomes infinitely more attractive than
	 * anon pages.  Try to detect this based on file LRU size.
	 */
	if (!cgroup_reclaim(sc)) {
		unsigned long total_high_wmark = 0;
		unsigned long free, anon;
		int z;

		free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES);
		file = node_page_state(pgdat, NR_ACTIVE_FILE) +
			   node_page_state(pgdat, NR_INACTIVE_FILE);

		for (z = 0; z < MAX_NR_ZONES; z++) {
			struct zone *zone = &pgdat->node_zones[z];
			if (!managed_zone(zone))
				continue;

			total_high_wmark += high_wmark_pages(zone);
		}

		/*
		 * Consider anon: if that's low too, this isn't a
		 * runaway file reclaim problem, but rather just
		 * extreme pressure. Reclaim as per usual then.
		 */
		anon = node_page_state(pgdat, NR_INACTIVE_ANON);
        //设置1代表只回收aone page,不回收file page
		sc->file_is_tiny =
			file + free <= total_high_wmark &&
			!(sc->may_deactivate & DEACTIVATE_ANON) &&
			anon >> sc->priority;
	}
    //回收的核心函数,后面文章专门分析
	shrink_node_memcgs(pgdat, sc);

	if (reclaim_state) {
		sc->nr_reclaimed += reclaim_state->reclaimed_slab;
		reclaim_state->reclaimed_slab = 0;
	}

	/* Record the subtree's reclaim efficiency */
	vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
		   sc->nr_scanned - nr_scanned,
		   sc->nr_reclaimed - nr_reclaimed);

    //这一轮回收到了页面
	if (sc->nr_reclaimed - nr_reclaimed)
		reclaimable = true;

    //只允许kswapd线程设置这些flag,因为只有kswapd能clear这些flag,避免混乱
    //比如memcg reclaim也能设置,没法保证kswapd肯定会被wakeup去clear这些标志
	if (current_is_kswapd()) {
		/*
		 * If reclaim is isolating dirty pages under writeback,
		 * it implies that the long-lived page allocation rate
		 * is exceeding the page laundering rate. Either the
		 * global limits are not being effective at throttling
		 * processes due to the page distribution throughout
		 * zones or there is heavy usage of a slow backing
		 * device. The only option is to throttle from reclaim
		 * context which is not ideal as there is no guarantee
		 * the dirtying process is throttled in the same way
		 * balance_dirty_pages() manages.
		 *
		 * Once a node is flagged PGDAT_WRITEBACK, kswapd will
		 * count the number of pages under pages flagged for
		 * immediate reclaim and stall if any are encountered
		 * in the nr_immediate check below.
		 */
        //设置PGDAT_DIRTY代表reclaim发现很多页面正在回写
		if (sc->nr.writeback && sc->nr.writeback == sc->nr.taken)
			set_bit(PGDAT_WRITEBACK, &pgdat->flags);

		/* Allow kswapd to start writing pages during reclaim.*/
        ////设置PGDAT_DIRTY代表reclaim发现很多脏页
		if (sc->nr.unqueued_dirty == sc->nr.file_taken)
			set_bit(PGDAT_DIRTY, &pgdat->flags);

		/*
		 * If kswapd scans pages marked for immediate
		 * reclaim and under writeback (nr_immediate), it
		 * implies that pages are cycling through the LRU
		 * faster than they are written so also forcibly stall.
		 */
		if (sc->nr.immediate)
			congestion_wait(BLK_RW_ASYNC, HZ/10);
	}

	/*
	 * Tag a node/memcg as congested if all the dirty pages
	 * scanned were backed by a congested BDI and
	 * wait_iff_congested will stall.
	 *
	 * Legacy memcg will stall in page writeback so avoid forcibly
	 * stalling in wait_iff_congested().
	 */
    //只允许kswapd线程设置LRUVEC_CONGESTED,因为只有kswapd能clear LRUVEC_CONGESTED,
    //比如memcg reclaim也能设置,没法保证kswap能唤醒去clear LRUVEC_CONGESTED,导致
    //direct reclaim阻塞在wait_iff_congested
	if ((current_is_kswapd() ||
	     (cgroup_reclaim(sc) && writeback_throttling_sane(sc))) &&
	    sc->nr.dirty && sc->nr.dirty == sc->nr.congested)
		set_bit(LRUVEC_CONGESTED, &target_lruvec->flags);

	/*
	 * Stall direct reclaim for IO completions if underlying BDIs
	 * and node is congested. Allow kswapd to continue until it
	 * starts encountering unqueued dirty pages or cycling through
	 * the LRU too quickly.
	 */
    //如果是非kswapd线程,且判定当前回收设置过拥塞flag,就要等待,所以direct reclaim
    //会被阻塞
	if (!current_is_kswapd() && current_may_throttle() &&
	    !sc->hibernation_mode &&
	    test_bit(LRUVEC_CONGESTED, &target_lruvec->flags))
		wait_iff_congested(BLK_RW_ASYNC, HZ/10);

    //如果需要继续回收,就goto again继续
	if (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed,
				    sc))
		goto again;

	/*
	 * Kswapd gives up on balancing particular nodes after too
	 * many failures to reclaim anything from them and goes to
	 * sleep. On reclaim progress, reset the failure counter. A
	 * successful direct reclaim run will revive a dormant kswapd.
	 */
	if (reclaimable)
		pgdat->kswapd_failures = 0;
}
should_continue_reclaim 

/*
 * Reclaim/compaction is used for high-order allocation requests. It reclaims
 * order-0 pages before compacting the zone. should_continue_reclaim() returns
 * true if more pages should be reclaimed such that when the page allocator
 * calls try_to_compact_pages() that it will have enough free pages to succeed.
 * It will give up earlier than that if there is difficulty reclaiming pages.
 */
static inline bool should_continue_reclaim(struct pglist_data *pgdat,
					unsigned long nr_reclaimed,
					struct scan_control *sc)
{
	unsigned long pages_for_compaction;
	unsigned long inactive_lru_pages;
	int z;

	/* If not in reclaim/compaction mode, stop */
	if (!in_reclaim_compaction(sc))
		return false;

	/*
	 * Stop if we failed to reclaim any pages from the last SWAP_CLUSTER_MAX
	 * number of pages that were scanned. This will return to the caller
	 * with the risk reclaim/compaction and the resulting allocation attempt
	 * fails. In the past we have tried harder for __GFP_RETRY_MAYFAIL
	 * allocations through requiring that the full LRU list has been scanned
	 * first, by assuming that zero delta of sc->nr_scanned means full LRU
	 * scan, but that approximation was wrong, and there were corner cases
	 * where always a non-zero amount of pages were scanned.
	 */
	if (!nr_reclaimed)
		return false;

    //compaction_suitable会检查水位是否已满足条件(要根据orderPAGE_ALLOC_COSTLY_ORDER
    //使用不同的watermark,如果不满足就不会返回success/continue
	/* If compaction would go ahead or the allocation would succeed, stop */
	for (z = 0; z <= sc->reclaim_idx; z++) {
		struct zone *zone = &pgdat->node_zones[z];
		if (!managed_zone(zone))
			continue;

        //满足了水位return false,代表不要继续shrink_node了
		switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) {
		case COMPACT_SUCCESS:
		case COMPACT_CONTINUE:
			return false;
		default:
			/* check next zone */
			;
		}
	}

	/*
	 * If we have not reclaimed enough pages for compaction and the
	 * inactive lists are large enough, continue reclaiming
	 */
    //上面水位检查不通过,且也没有reclaim足够的page来做compaction,那就继续reclaim吧
	pages_for_compaction = compact_gap(sc->order);
	inactive_lru_pages = node_page_state(pgdat, NR_INACTIVE_FILE);
	if (get_nr_swap_pages() > 0)
		inactive_lru_pages += node_page_state(pgdat, NR_INACTIVE_ANON);

	return inactive_lru_pages > pages_for_compaction;
}

 compaction_suitable会判定当前水位是否满足order申请,如果满足了那么COMPACT_SUCCESS,说明也不需要继续compact了;如果不满了说明还没有回到足够order申请的内存,逻辑会继续往下走到inactive_lru_pages > pages_for_compaction逻辑判定,如果inactive lru中有大于2被申请order的页面,那就继续扫描回收

参考文章:

[PATCH v2 4/4] mm/vmscan: Don't mess with pgdat->flags in memcg reclaim. - Andrey Ryabinin

Linux 内存管理_workingset内存_jianchwa的博客-优快云博客

Linux 6.12 源码深度剖析: shrink_node Linux 6.12内核中,shrink_node是内存回收的核心引擎,负责在内存紧张时扫描NUMA节点的LRU链表,回收冷页并协调Cgroup与I/O子系统。其关键机制包括MGLRU无锁设计、基于cgroup的分级回收、I/O拥塞检测与限流(reclaim_throttle),有效防止直接回收风暴导致的CPU飙升与系统假死。通过调优watermark_scale_factor、启用MGLRU及优化脏页回写参数,可显著提升大内存系统的稳定性与响应性能。 阅读详情

相关推荐

Linux页框回收机制详解:从LRU链表到内存调优实践

物理内存是影响系统性能的关键资源,Linux内核通过分页机制管理物理页框,但内存并非等到耗尽才需要回收,而是由内核依据水位阈值提前触发回收动作。页框回收(PFRA)作为内存管理的核心机制,负责决定哪些页面可以释放、哪些必须保留以及按什么顺序处理,其实现涉及LRU链表、kswapd与direct reclaim两条路径、反向映射与回写等多个环节。理解这些底层原理,对内核源码阅读、性能调优和内存抖动问题排查至关重要。本文从内存管理的基础概念切入,逐步讲解页框回收的设计思路、LRU链表运作方式、完整回收流程,并介

weixin_33507732的博客 176

重写-linux内存管理-伙伴分配器(三)内存回收

申请分配页的时候,页分配器首先尝试使用低水线分配页。如果使用低水线分配失败,说明内存轻微不足,页分配器将会唤醒所有符合分配条件的内存节点的页回收线程,异步回收页,然后尝试使用最低水线分配页。如果分配失败,说明内存严重不足,页分配器将会进行内存碎片整理,整理后尝试使用最低水线分配页。如果分配失败,说明内存不够用了,需要回收一些暂时用不上的内存,页分配器将会直接回收页。后面才会oom等等。也就是说,存在内存异步回收和内存同步回收。

jianjian的博客 1265

Linux内核物理内存管理:伙伴系统、SLUB分配器与NUMA架构详解

物理内存管理是操作系统核心基础,通过内存管理单元实现虚拟地址到物理地址的转换。其核心原理包括页帧划分、内存管理区划分和伙伴系统算法,通过SLUB分配器优化小对象内存分配。在NUMA架构下,内存管理需要处理非一致性内存访问问题,通过节点本地化分配提升性能。这些技术为系统性能优化、驱动开发和内核定制提供基础支撑,特别是在Linux内核开发中,深入理解物理内存探测、伙伴系统碎片处理和SLUB分配器机制至关重要。本文通过实际代码示例系统解析Linux物理内存管理的完整架构与工程实践。

weixin_34326429的博客 333

linux内核 内存回收函数do_try_to_free_pages源码解析

记录一下学习linux 内存回收关键函数do_try_to_free_pages的过程。源码版本:linux 5.10。

qq_41276711的博客 351

Linux内存管理(65):shrink_node 详解

在页面回收简介和 kswpd(1)直接页面回收机制:在内核态里调用页面分配接口函数 alloc_pages() 分配物理页面时,由于系统内存短缺,不能满足分配请求,因此内核会直接进入页面回收机制,尝试回收内存来解决当前的燃眉之急,这就是直接页面回收机制。周期性回收内存机制:这是 kswapd 内核线程的工作职责。当内核路径调用 alloc_pages() 分配物理页面时,由于系统内存短缺,没法在低水位情况下分配出内存,因此会唤醒 kswapd 内核线程来异步回收内存。

私房菜 2万+

Linux内存管理(66):shrink_list 详解(1)

在在一文主要分析了 shrink_lruvec,并知道在get_scan_count() 中根据扫描平衡条件,确定了anon/file LRU 扫描页数,并最终会 shrink_list() 进行深入的回收处理。本文将继续分析页面回收 shrink_lruvec() 部分的和流程。

私房菜 1446

Linux内存管理:(七)页面回收机制

文章说明:Linux内核版本:5.0架构:ARM64参考资料及图片来源:《奔跑吧Linux内核》

qq_58538265的博客 2126

linux那些事之shrink_node

shrink_node为实施内存回收的一个关键节点处理: 不管是kswapd回收还是慢速申请直接回收都会通过shrink_node进行内存回收, shrink_node shrink_node主要是根据scan_control 控制内存回收力度,来决定具体回收的行为和策略,后续通过shrink_node_memcgs根据scan_control回收策略决定LRU和slab回收行为: static void shrink_node(pg_data_t *pgdat, struct scan_c

weixin_42730667的博客 1869

Linux内存管理全程解析:从malloc到缺页异常与物理页分配

虚拟内存是现代操作系统的基石,它通过按需分配机制让每个进程都拥有独立的地址空间,而物理页则作为稀缺资源被内核精打细算地管理。当程序调用malloc申请内存时,内核并不会立即分配物理页,而是先建立虚拟内存区域(VMA)元数据,直到进程真正访问该地址才会触发缺页异常。缺页异常是内存管理的核心枢纽,它根据页表项状态区分匿名页、文件映射与写时复制场景,并驱动物理页分配器从伙伴系统或slab缓存中获取内存。理解这一链路,不仅有助于阅读内核源码,还能在实际排障中解读free、vmstat、/proc/meminfo等指

weixin_34384557的博客 539

Linux内存管理(76):页面回收总结

在页面回收简介和 kswapd详解(1)一文中简单列举了Linux 内核中触发页面回收的机制,详细剖析了 kswapd 内核线程的初始化和唤醒过程,了解了唤醒 kswapd 内核线程的 3 种方式。图1是直接内存回收唤醒 kswapd 的大致流程。在kswapd详解(2)一文中详细地剖析了唤醒 kswapd 内核线程后,线程核心处理函数 kswapd() 的执行过程和注意点。图2是唤醒kswapd 和 kswapd() 处理的大致流程。在shrink_node 详解。

私房菜 1729

linux内存之水线设置和page回收

此函数最终会将满足条件的page添加到链表folio_list上,而此链表之前的成员数据基本已经从此链表上删除了,后续与活动页一样调用free_unref_page_list函数将page释放到freelist链表上。到此page的回收流程大体就结束了,后续针对细节再进行更深入的分析。唯一会进行释放page的操作是folio_has_private且引用计数为0时,会直接释放此page页。这里内存回收涉及到page回收和缓存回收,这里只关注page的回收,后面再研究slab的回收。

bruk_spp的博客 208

Linux内存管理进阶:VMA、缺页异常、SLUB与页面回收

Linux内存管理是系统稳定性和性能优化的核心课题。进程的虚拟地址空间通过mm_struct与VMA来刻画,每一段映射都对应一个VM Area,理解其合并、分裂与查找机制,是排查VMA数量膨胀和RSS异常的基础。缺页异常是虚拟地址真正落地的必经关卡,按PTE状态分为匿名页、文件映射和写时复制等路径,通过majflt与minorfault区分IO瓶颈。内核自身分配小对象时并未直接使用伙伴系统,而是借助SLUB缓存复用对象,降低开销与碎片化。当内存压力上升时,kswapd与直接回收协同工作,配合LRU链表、sw

weixin_34389926的博客 203

Linux 内核参数:vmstat

Linux内存管理统计机制分析 本文深入分析了Linux内核中的内存管理统计机制,重点解析了/proc/vmstat节点的实现原理。该节点通过多个全局数组(vm_zone_stat、vm_numa_stat、vm_node_stat)和数据结构(zone、pglist_data)中的计数器,全面记录了系统内存的使用情况,包括: 内存区域统计:空闲页面、活跃/非活跃页面、不可回收页面等 节点统计:slab页面、工作集、脏页等 系统事件统计:缺页中断、页面回收、交换活动等 文章详细梳理了统计数据的采集流程、数据

私房菜 2011

Linux内核内存回收:kswapd、水位线与MemAvailable排查

Linux内存管理的核心议题之一,是在有限物理内存中平衡缓存、匿名页与文件页的回收代价。其原理围绕page cache、LRU链表与min/low/high水位线展开:kswapd后台回收与业务进程触发的直接回收共同决定回收时机,swappiness则调节匿名页换出倾向。技术价值在于避免OOM killer、减少卡顿并提升服务器稳定性。线上容器、数据库和中间件场景中,MemAvailable、pgscan_direct、pgmajfault等指标可用于定位回收失效与内存泄漏。理解从分配路径、shrink_n

weixin_42116058的博客 284

从标准到实战:详解IEC 61000-4-2下的ESD电路防护设计

本文深入解析IEC 61000-4-2标准下的ESD电路防护设计,从静电防护的基础原理到实战应用。详细介绍了接触放电与空气放电的区别、防护器件选型要点(如TVS管和压敏电阻)以及PCB布局的黄金法则,帮助工程师有效提升电子产品的抗静电能力,确保设备在严苛环境下的稳定运行。

weixin_33704234的博客 512

深入解析V4L2框架与高通KMD在Camera驱动中的协同设计

本文深入解析了V4L2框架与高通KMD在Camera驱动中的协同设计。V4L2作为Linux内核标准视频驱动框架,提供了统一的设备抽象与数据流管理;而高通KMD则在其基础上,通过引入CRM等核心模块,构建了一套针对移动平台复杂相机系统的高效内核态驱动架构,实现了硬件配置与执行的解耦与智能调度。

qq_27496129的博客 1145

Linux 内存控制器(memcg)内部实现备忘:记账、换入换出、页迁移与典型测试全解析

本文以内核源码树中的 [Documentation/admin-guide/cgroup-v1/memcg_test.rst](https://link.gitcode.com/i/07c23815cf088e9f7cb873121ad25f1b)(Memcg 实现备忘,原文档基于 2.6.33-rc7-mm,最后更新于 2010/2)为骨架,结合当前仓库中 memcg 相关源码逐条印证。它面向希

gitblog_00160的博客 358

基于STM32L4XX、HAL库的 L76KB-A58定位模块驱动程序设计

/ 确保字符串终止。// 缓冲区溢出,重置。// 重置缓冲区索引。支持GPS、GLONASS、Galileo、北斗和QZSS多系统定位。case 1: // UTC时间。// 配置GPS模块(可选)// 查找GGA语句。// 启动UART接收。// USART1初始化函数。内置LNA和SAW滤波器。

zhusl6688的博客 349

Linux内核内存管理深度:从伙伴系统到SLUB、缺页与回收机制

内存管理是Linux内核中决定系统稳定性与性能的核心子系统,它贯穿物理页面分配、虚拟地址映射和进程地址空间管理。内核通过伙伴系统以2的幂次管理连续物理页,SLUB分配器则针对小对象提供高速缓存,避免页面浪费;当需要大块虚拟连续内存时,vmalloc通过页表映射弥合物理不连续的缺口。而用户态进程的首访内存依赖缺页异常处理,内核在此路径上完成匿名页、文件页及写时复制的按需分配。当物理内存不足时,kswapd与直接回收机制依据水位线触发LRU扫描,回收文件页或匿名页。理解这些机制有助于排查内存碎片、slab增长异

weixin_34267123的博客 301

<IBM DB2>《DB2 官方监控脚本 2022版本》

DB2 监控脚本

Else 的博客 670

069_死区效应对输出电压畸变的补偿思路

死区效应导致逆变器输出电压在过零点出现台阶畸变,引发THD升高。其本质是死区期间续流二极管钳位造成的非线性误差,与电流方向、负载大小、母线电压耦合。补偿需结合前馈(基于电流方向自适应调整偏置)与反馈(抑制残余谐波),关键在于准确判断电流方向(采用滞环滤波避免跳变)、合理设置补偿量(随负载动态调整),并注意补偿位置、极性及限幅防漂移。调试应通过差分探头、FFT频谱等手段验证效果,最终实现全负载范围内的低畸变输出。

2401_88858637的博客 21

Linux内核物理内存管理:从伙伴系统到SLUB分配器深度解析

内存管理是操作系统核心基础概念,通过虚拟内存和物理内存映射机制实现进程隔离与资源分配。其原理基于硬件MMU和页表转换,将连续的虚拟地址空间映射到可能不连续的物理内存页。在技术价值层面,高效的内存管理直接影响系统性能、稳定性和资源利用率,特别是在处理大规模数据和高并发场景时尤为关键。应用场景涵盖从嵌入式设备到大型服务器的各种计算环境,涉及进程创建、文件缓存、驱动分配等核心操作。本文聚焦Linux内核物理内存管理,深入解析伙伴系统的大块内存分配机制和SLUB分配器的小对象高效管理,结合实际工程实践探讨内存碎片优

weixin_30787531的博客 363

零基础学习simulink-- 四旋翼和六旋翼无人机的建模与动力学分析

通过上述代码实现,您可以逐步创建和搭建一个多旋翼无人机(如四旋翼、六旋翼)的动力学模型,并结合自适应控制器进行仿真。该模型不仅考虑了无人机的基本动力学行为,还引入了空气阻力、螺旋桨之间的相互作用以及气流干扰等复杂效应,使得仿真结果更加接近实际情况。Simulink 提供了强大的建模和仿真工具,使得控制系统工程师能够快速构建复杂的控制算法,并将其应用于实际工程中。多旋翼无人机动力学建模:建立四旋翼和六旋翼无人机的动力学模型,包括平移运动和旋转运动方程。升力和扭矩模型。

amy_mhd的博客 386

Linux内核Buddy分配器详解:物理页分配机制与调试实战

物理内存是计算机最宝贵的资源,如何高效分配和回收页面是操作系统内核的核心难题。Linux内核采用伙伴系统(Buddy System)管理物理页,通过order阶数将空闲块按2的幂次分桶,并借助水位线(watermark)与迁移类型(migratetype)机制平衡分配延迟与内存碎片化。理解物理页分配(alloc_page)的完整链路,对驱动开发、嵌入式移植、性能调优及排查OOM问题都至关重要。本文从基础概念出发,深入剖析Buddy分配器从快速路径到慢速路径、从free_area链表到PCP缓存、从内存规整到

weixin_34221276的博客 308

RAP 值帮助实战:用 CDS 注解把 Fiori Elements 的输入体验做得又快又准

本文系统介绍了如何在SAP RAP应用中实现高效的值帮助(Value Help)功能。通过复用标准CDS View和自定义View Entity,开发者可以快速为字段添加弹窗选择、搜索和下拉框功能。文章详细讲解了三种核心实现方式:复用标准值帮助CDS View实现快速集成;构建自定义View Entity支持企业特定编码;利用搜索注解(@Search)和下拉框注解(@ObjectModel)优化用户体验。特别强调了文本显示、模糊搜索和小结果集下拉等实用技巧,并提供了可直接复用的国家代码值帮助示例。这些方法能

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 6465

华为 MetaERP 总账模块依托 “交易即核算” 的事件驱动架构,与 Oracle EBS 相比,更强调业务事件自动触发财务动作、实时数据同步和智能规则引擎,实现业务与财务的深度融合

华为MetaERP总账模块采用"交易即核算"架构,相比Oracle EBS实现了三大突破:1)业务事件自动触发财务动作,如采购收货自动生成暂估凭证;2)业务财务数据实时同步,支持即时分析;3)内置智能规则引擎,实现自动匹配、核销和结转。该模块覆盖采购、销售、资产、薪酬等全业务场景,支持多维核算和关联交易自动抵消,显著提升核算效率与准确性。其中采购暂估、销售结转等场景实现全自动化处理,较EBS减少80%手工操作。

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

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值