物理内存分配

news2024/12/22 20:07:52

目录

内核物理内存分配接口

内存分配行为(物理上)

内存分配的行为操作  

内存 三个水位线

水线计算

水位线影响内存分配行为

内存分配核心__alloc_pages

释放页



1、内核物理内存分配接口

struct page *alloc_pages(gfp_t gfp, unsigned int order);

用于向底层伙伴系统申请2的order次幂个物理内存页;gfp是分配行为的修饰符;该函数返回值时一个struct page类型的指针用于指向申请内存中第一个物理内存页。

申请

#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)

底层还是依赖了 alloc_pages 函数,只不过 order 指定为 0;

vmalloc 分配机制底层就是用的 alloc_page

以上返回的是物理页,而CPU直接访问的是虚拟页

unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
{
 struct page *page;
    // 不能在高端内存中分配物理页,因为无法直接映射获取虚拟内存地址
 page = alloc_pages(gfp_mask & ~__GFP_HIGHMEM, order);
 if (!page)
  return 0;
    // 将直接映射区中的物理内存页转换为虚拟内存地址
 return (unsigned long) page_address(page);
}

page_address 函数用于将给定的物理内存页转换成虚拟地址,这里的地址是直接映射区 ;如果物理内存处于高端内存,不能直接转换,通过alloc_pages函数申请物理内存页,再调用kmap映射将page映射到内核虚拟地址空间。

分配单页的函数,依赖于 __get_free_pages 函数,参数 order 指定为 0 

#define __get_free_page(gfp_mask) \
  __get_free_pages((gfp_mask), 0)

申请内存并初始化为0 

unsigned long get_zeroed_page(gfp_t gfp_mask)
{
 return __get_free_pages(gfp_mask | __GFP_ZERO, 0);
}

从DMA 内存区域申请物理页

unsigned long __get_dma_pages(gfp_t gfp_mask, unsigned int order);

释放

释放多页

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

释放单页 

#define __free_page(page) __free_pages((page), 0)
#define free_page(addr) free_pages((addr), 0)

2、内存分配行为(物理上)

从哪里分配gfp_mask  (GFP 是 get free page )

根据物理内存功能不同,将 NUMA 节点内的物理内存划分为:ZONE_DMA,ZONE_DMA32,ZONE_NORMAL,ZONE_HIGHMEM 这几个物理内存区域。

gfp_mask 中的低 4 位用来表示应该从哪个物理内存区域 zone 中获取内存页 page

#define ___GFP_DMA      0x01u
#define ___GFP_HIGHMEM  0x02u
#define ___GFP_DMA32    0x04u
#define ___GFP_MOVABLE  0x08u

物理内存的分配主要是落在 ZONE_NORMAL 区域中,如果我们不指定物理内存的分配区域,那么内核会默认从 ZONE_NORMAL 区域中分配内存;

ZONE_HIGHMEM -> ZONE_NORMAL -> ZONE_DMA 的顺序依次降级

如果 ZONE_NORMAL 区域中的空闲内存不够,内核则会降级到 ZONE_DMA 区域中分配。

gfp_zone 

用于将我们在物理内存分配接口中指定的 gfp_mask 掩码转换为物理内存区域

static inline enum zone_type gfp_zone(gfp_t flags)
{
 enum zone_type z;
 int bit = (__force int) (flags & GFP_ZONEMASK);

 z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) &
      ((1 << GFP_ZONES_SHIFT) - 1);
 VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
 return z;
}

3、内存分配的行为操作  

/include/linux/gfp.h

#define ___GFP_RECLAIMABLE 0x10u
#define ___GFP_HIGH  0x20u
#define ___GFP_IO  0x40u
#define ___GFP_FS  0x80u
#define ___GFP_ZERO  0x100u
#define ___GFP_ATOMIC  0x200u
#define ___GFP_DIRECT_RECLAIM 0x400u
#define ___GFP_KSWAPD_RECLAIM 0x800u
#define ___GFP_NOWARN  0x2000u
#define ___GFP_RETRY_MAYFAIL 0x4000u
#define ___GFP_NOFAIL  0x8000u
#define ___GFP_NORETRY  0x10000u
#define ___GFP_HARDWALL  0x100000u
#define ___GFP_THISNODE  0x200000u
#define ___GFP_MEMALLOC  0x20000u
#define ___GFP_NOMEMALLOC 0x80000u
  • __GFP_RECLAIMABLE  指定分配的页面是可以回收的
  • __GFP_MOVABLE 分配的页面可以移动
  • __GFP_HIGH 内存分配请求是高优先级,不允许失败
  • __GFP_IO 在分配物理内存的时候,可以发起IO操作;
  • __GFP_FS 允许内核执行底层文件系统操作
  • __GFP_ZERO 内存初始化后,将初始化填充字节0
  • __GFP_ATMOIC 分配时不允许睡眠,如中断程序中。不能被重新安全调度的上下文。
  • __GFP_DIRECT_RECLAIM 内核分配时,可以进行内存回收
  • __GFP_KSWAPD_RECLAIM 分配内存时,如果剩余内存容量在WMARK_MIN与WMARK_LOW之间,会唤醒kswapd进程开始异步回收,直到剩余内存高于WMARK_HIGH为止。
  • __GFP_NOWARN 当内核分配失败时,抑制内核的分配失败错误警告。
  • __GFP_RETRY_MAYFAIL 内核分配失败,运行重试,重试若干次后停止。
  • __GFP_NORETRY 表示 内存分配失败,不允许重试
  • __GFP_NOFAIL 分配失败时一直重试直到成功为止
  • __GFP_HARDWALL 内存分配行为只能在当前分配到的CPU关联的NUMA节点上进行分配,当进程可以运行的CPU受限制时,才有意义。
  • __GFP_THISNODE 只能在当前NUMA几点或者指定NUMA节点中分配
  • __GFP_MEMALLOC 可以从所有内存区域获取内存,包括紧急预留内存,但是需要保证会很快释放
  • __GFP_NOMEMALLOC禁止从紧急预留内存中获取内存;优先级高于__GFP_MEMALLOC 

为了简化使用以上修饰符,内核提供以下组合,避免出错

#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)
#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)
#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM)
#define GFP_NOIO (__GFP_RECLAIM)
#define GFP_NOFS (__GFP_RECLAIM | __GFP_IO)
#define GFP_USER (__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
#define GFP_DMA  __GFP_DMA
#define GFP_DMA32 __GFP_DMA32
#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM)

 GFP_ATOMIC,表示内存分配行为必须是原子的,是高优先级;不允许睡眠,如果内存不够则从紧急预留内存中分配。

GFP_KERNEL 常用,可能会阻塞;可以运行内核置换出一些不活跃的内存页到磁盘中。适用于可以安全调度的进程上下文中。

GFP_NOIO和GFP_NO_FS 禁止内核在分配内存时进行磁盘IO和文件IO操作

GFP_USER 用于映射到用户空间的内存分配,可以被内核或者硬件直接访问,如硬件设备会将Buffer直接映射到用户空间中。

GFP_DMA和GFP_DMA32表示 从DMA和DMA32中获取适用于DMA的内存页。

GFP_HIGHUSER用于给用户空间分配高端内存,因为在用户虚拟内存中,都是通过页表来访问非直接映射的高端内存。

4、内存 三个水位线

内存水位影响内存分配的行为

enum zone_watermarks {
 WMARK_MIN,
 WMARK_LOW,
 WMARK_HIGH,
 NR_WMARK
};
struct zone {
    // 物理内存区域中的水位线
    unsigned long _watermark[NR_WMARK];
}

物理剩余内存高于WMARK_HIGH时,内存非常充足

LOW<内存<HIGH 内存有一定的消耗,但不影响分配

MIN<内存<LOW 内存有压力,但是可以满足进程此时内存分配要求,分配后会唤醒kswap进程开始回收内存,直到剩余内存高于HIGH为止(异步完成)。

内存<MIN 时,内核直接进行回收,此时内存回收任务由请求进程同步完成。

最低水线以下的内存称为紧急预留内存;

进程设置标志PF_MEMALLOC可以使用仅仅预留内存;内存管理子系统以外不应该使用这个标志,典型的例子是页回收线程kswap,在页回收中可能要申请内存。 

水线计算参数

1)min_free_kbytes 最小空闲字节数,

        默认值是4* \sqrt{lowmemkbytes},并且限制在范围[128,65535]以内。

        其中lowmem_kbytes是低端内存大小,单位是KB

        可以通过文件/proc/sys/vm/min_free_kbytes设置最小空闲字节数

        源码文件 mm/page_alloc.c 中函数 init_zone_wmark_min

2)watermark_scale_factor 水线缩放因子。默认值为10,

        通过/proc/sys/vm/watermark_scale_factor修改水线缩放因子,范围[1,1000]

水线计算

mm/page_alloc.c中函数__setup_per_zone_wmarks

1、最低水线计算方法

1)min_free_pages = min_free_kbytes对应的页数

2)lowmem_pages =所有低端内存区域中伙伴分配器管理的页数总和;

3)高端内存区域的最低水线= zone->managed_pages/1024,并且限制范围[32,128]以内

         zone->managed_pages是内存区域伙伴分配器管理的页数,在内核初始化过程中引导分配器分配出去的物理页。

4)低端内存区域水线= min_free_pages * zone->managed_pages/lowmem_pages 即把min_free_pages按比例分配到每个低端内存区域;

2、计算低水线和高水线方法

  1. 增量 = (最低水线/4,zone->managed_pages * watermark_scale_factor/1000)取最大值
  2. 最低水线 = 低水线 + 增量
  3. 最高水线 = 高水线 + 增量*2

5、水位线影响内存分配行为

#define ALLOC_WMARK_MIN     WMARK_MIN
#define ALLOC_WMARK_LOW     WMARK_LOW
#define ALLOC_WMARK_HIGH    WMARK_HIGH
#define ALLOC_NO_WATERMARKS 0x04 /* don't check watermarks at all */

#define ALLOC_HARDER         0x10 /* try to alloc harder */
#define ALLOC_HIGH       0x20 /* __GFP_HIGH set */
#define ALLOC_CPUSET         0x40 /* check for correct cpuset */

#define ALLOC_KSWAPD        0x800 /* allow waking of kswapd, __GFP_KSWAPD_RECLAIM set */

ALLOC_NO_WATERMARKS 表示不考虑三个水位线

 ALLOC_WMARK_HIGH 表示内存必须达到HIGH要求

ALLOC_WMARK_LOW 表示内存必须达到LOW要求

ALLOC_WMARK_MIN  表示内存必须达到MIN要求

ALLOC_HARDER         表示内存分配,放宽内存分配规则的限制,其实就是降低MIN水位,使内存分配最大可能成功。

ALLOC_HIGH gfp_t掩码设置__GFP_HIGH时才有作用,表示当前内存分配请求是高优先级的,不允许失败,可以从紧急预留内存中分配。

ALLOC_CPUSET          只能在当前进程所允许的CPU所关联的NUMA节点进行分配。如:cgroup功能。

ALLOC_KSWAPD表示允许唤醒NUMA节点中的KSWAPD进程,异步内存回收,每个NUMA几点分配一个kswapd进程用于回收不经常使用的页面。

6、内存分配核心__alloc_pages

7、释放页

void __free_pages(struct page *page, unsigned int order)
{
	if (put_page_testzero(page))
		free_the_page(page, order);
}


static inline void free_the_page(struct page *page, unsigned int order)
{
	if (order == 0)		/* Via pcp? */
		free_unref_page(page);
	else
		__free_pages_ok(page, order);
}

先把引用计数减一,只有页的引用计数变成0,才真正释放页;

如果阶是0 不还给伙伴系统,而是作为冷热页添加到每处理器页集合中,如果页集合中页数量大于或等于高水线,那么批量返回给伙伴分配器;

如果阶大于0 调用__free_pages_ok释放页;

static void free_unref_page_commit(struct page *page, unsigned long pfn)
{
	struct zone *zone = page_zone(page);//获取zone
	struct per_cpu_pages *pcp;//per-cpu
	int migratetype;

	migratetype = get_pcppage_migratetype(page);
	__count_vm_event(PGFREE);

	/*
	 * We only track unmovable, reclaimable and movable on pcp lists.
	 * Free ISOLATE pages back to the allocator because they are being
	 * offlined but treat HIGHATOMIC as movable pages so we can get those
	 * areas back if necessary. Otherwise, we may have to free
	 * excessively into the page allocator
	 */
	//每处理器只存放,不可移动,可回收和可移动三种类型,超过这三种类型处理方法
	//1)如果是隔离类型的页,直接释放
	//2)其他类型的页添加到可移动链表中,page->index保存真实迁移类型。
	if (migratetype >= MIGRATE_PCPTYPES) {
		if (unlikely(is_migrate_isolate(migratetype))) {
			free_one_page(zone, page, pfn, 0, migratetype);
			return;
		}
		migratetype = MIGRATE_MOVABLE;
	}
	//添加到per-cpu中
	pcp = &this_cpu_ptr(zone->pageset)->pcp;
	list_add(&page->lru, &pcp->lists[migratetype]);
	pcp->count++;//数量++
	//如果count大于或等于高水线,批量还给伙伴分配器
	if (pcp->count >= pcp->high) {
		unsigned long batch = READ_ONCE(pcp->batch);
		free_pcppages_bulk(zone, batch, pcp);
	}
}

__free_pages_ok 最终调用__free_one_page

如果伙伴系统是空闲的,并且伙伴在同一个内存区域,那么和伙伴合并;

隔离块和其他类型的页块不能合并

假设最后合并的页阶数是order,如果order小于MAX_ORDER-2 则检查 order+1阶的伙伴是否有空闲,如果有空闲,那么order阶的伙伴可能正在释放,很快合并成order+2阶的块;

为了防止当前块很快被分配出去,把当前页块添加到空闲链表的尾部。 

static void __free_pages_ok(struct page *page, unsigned int order)
{
	unsigned long flags;
	int migratetype;
	unsigned long pfn = page_to_pfn(page);

	if (!free_pages_prepare(page, order, true))
		return;

	migratetype = get_pfnblock_migratetype(page, pfn);
	local_irq_save(flags);
	__count_vm_events(PGFREE, 1 << order);
	free_one_page(page_zone(page), page, pfn, order, migratetype);
	local_irq_restore(flags);
}

static void free_one_page(struct zone *zone,
				struct page *page, unsigned long pfn,
				unsigned int order,
				int migratetype)
{
	spin_lock(&zone->lock);
	if (unlikely(has_isolate_pageblock(zone) ||
		is_migrate_isolate(migratetype))) {
		migratetype = get_pfnblock_migratetype(page, pfn);
	}
	__free_one_page(page, pfn, zone, order, migratetype);
	spin_unlock(&zone->lock);
}


static inline void __free_one_page(struct page *page,
		unsigned long pfn,
		struct zone *zone, unsigned int order,
		int migratetype)
{
	unsigned long combined_pfn;
	unsigned long uninitialized_var(buddy_pfn);
	struct page *buddy;
	unsigned int max_order;
	struct capture_control *capc = task_capc(zone);

	//可移动性分组的阶数
	max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);

	VM_BUG_ON(!zone_is_initialized(zone));
	VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page);

	VM_BUG_ON(migratetype == -1);
	if (likely(!is_migrate_isolate(migratetype)))
		__mod_zone_freepage_state(zone, 1 << order, migratetype);

	VM_BUG_ON_PAGE(pfn & ((1 << order) - 1), page);
	VM_BUG_ON_PAGE(bad_range(zone, page), page);

continue_merging:
	//如果伙伴系统是空闲的,和伙伴合并,重复
	while (order < max_order - 1) {
		if (compaction_capture(capc, page, order, migratetype)) {
			__mod_zone_freepage_state(zone, -(1 << order),
								migratetype);
			return;
		}
		buddy_pfn = __find_buddy_pfn(pfn, order);//得到伙伴的起始物理页号
		buddy = page + (buddy_pfn - pfn);//得到伙伴的第一页的page实例

		if (!pfn_valid_within(buddy_pfn))
			goto done_merging;
		//查询伙伴是空闲并且在相同的区域内存
		if (!page_is_buddy(page, buddy, order))
			goto done_merging;
		/*
		 * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
		 * merge with it and move up one order.
		 */
		//开启了调试页分配器配置宏CONFIG_DEBUG_PAGEALLOC,伙伴充当警戒页
		if (page_is_guard(buddy))
			clear_page_guard(zone, buddy, order, migratetype);
		else//伙伴是空闲的并且在相同内存区
			del_page_from_free_area(buddy, &zone->free_area[order]);
		combined_pfn = buddy_pfn & pfn;
		page = page + (combined_pfn - pfn);
		pfn = combined_pfn;
		order++;
	}
	//阻止把隔离类型的页块和其他类型的页块合并
	if (max_order < MAX_ORDER) {
		/* If we are here, it means order is >= pageblock_order.
		 * We want to prevent merge between freepages on isolate
		 * pageblock and normal pageblock. Without this, pageblock
		 * isolation could cause incorrect freepage or CMA accounting.
		 *
		 * We don't want to hit this code for the more frequent
		 * low-order merging.
		 */
		if (unlikely(has_isolate_pageblock(zone))) {
			int buddy_mt;

			buddy_pfn = __find_buddy_pfn(pfn, order);
			buddy = page + (buddy_pfn - pfn);
			buddy_mt = get_pageblock_migratetype(buddy);
			//如果是隔离类型的页块,另一个是其他类型不能合并
			if (migratetype != buddy_mt
					&& (is_migrate_isolate(migratetype) ||
						is_migrate_isolate(buddy_mt)))
				goto done_merging;
		}
		max_order++;//继续合并
		goto continue_merging;
	}

done_merging:
	set_page_order(page, order);

	/*
	 * If this is not the largest possible page, check if the buddy
	 * of the next-highest order is free. If it is, it's possible
	 * that pages are being freed that will coalesce soon. In case,
	 * that is happening, add the free page to the tail of the list
	 * so it's less likely to be used soon and more likely to be merged
	 * as a higher order page
	 */
	if ((order < MAX_ORDER-2) && pfn_valid_within(buddy_pfn)
			&& !is_shuffle_order(order)) {
		struct page *higher_page, *higher_buddy;
		combined_pfn = buddy_pfn & pfn;
		higher_page = page + (combined_pfn - pfn);
		buddy_pfn = __find_buddy_pfn(combined_pfn, order + 1);
		higher_buddy = higher_page + (buddy_pfn - combined_pfn);
		if (pfn_valid_within(buddy_pfn) &&
		    page_is_buddy(higher_page, higher_buddy, order + 1)) {
			add_to_free_area_tail(page, &zone->free_area[order],
					      migratetype);
			return;
		}
	}

	if (is_shuffle_order(order))
		add_to_free_area_random(page, &zone->free_area[order],
				migratetype);
	else
		add_to_free_area(page, &zone->free_area[order], migratetype);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1022304.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【go语言基础】go类型断言 type switch + case,t := x.(type)

有这么一个场景&#xff0c;当你在和用户对接的时候&#xff0c;调取第三方接口&#xff0c;但是第三方接口的时常变化的&#xff0c;比如从string类型变为int&#xff0c;这个时候你需要再去判断类型&#xff0c;获取第三方接口的参数。比较麻烦。 针对这一场景&#xff0c;g…

爬虫工具篇-ProxyBroker-代理IP管理

前言 随着互联网的不断发展&#xff0c;大量的信息和数据都被存储在各种不同的网站上。为了获取这些信息和数据&#xff0c;我们经常需要使用爬虫工具来自动化地从网站上抓取数据。然而&#xff0c;在一些情况下&#xff0c;网站可能会采取一些反爬虫措施&#xff0c;例如向IP…

AG35学习笔记(一):debug串口抓取模组log、debug串口测试AT指令、echo命令通过串口发送16进制数据

目录 一、概述二、抓取模组log2.1 硬件接口2.2 用户登录2.3 相关指令 三、测试AT指令3.1 查看端口3.2 进入模式 四、串口发16进制echo使用 一、概述 二、抓取模组log 在之前记录了通过USB&#xff0c;使用移远工具Qwinlog来抓取log&#xff08;3.3 抓取模组log&#xff09;。…

21天学会C++:Day11----运算符重载

CSDN的uu们&#xff0c;大家好。这里是C入门的第十一讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 知识引入 2. 运算符重载 2.1 operator<() 2.2 operator() 2.3 o…

上市公司的公众环境关注度(2011-2022年)

随着互联网的普及&#xff0c;公众越来越多地通过互联网表达看法。国内外一些学者在研究中采用Google搜索引擎搜索功能构建指标&#xff0c;表达公众需求和关注程度(Kahn & Kotchen, 2011; Choi & Varian, 2012; 郑思齐等&#xff0c; 2013) 百度搜索在中国内地的市场占…

高速、低功耗模拟开关芯片 MS703D

MS703D 是一款高速、低功耗模拟开关芯片&#xff0c;其工作电压范围 是 1.8 至 5.5V 。其具有低码间偏移、高通道噪声隔离度以及大带 宽特性。 主要应用范围包括&#xff1a;手持设备和消费电子&#xff0c;如手机、数码相 机、笔记本电脑等。 主要特点  3V 下导通电…

开源日报 0824 | 构建UI组件和页面的前端工作坊

Storybook 是一个用于构建 UI 组件和页面的前端工作坊&#xff0c;支持多种主流框架&#xff0c;提供丰富的插件&#xff0c;具有可配置性强和扩展性好的特点。 storybookjs/storybook Stars: 79.9k License: MIT Storybook 是一个用于构建 UI 组件和页面的前端工作坊&#x…

px to rem rpx vw中文文档 |px自动转换rem插件

【px to rem & rpx & vw】项目地址&#xff1a; https://github.com/cipchk/vscode-cssrem/blob/HEAD/README.zh-CN.md 作者&#xff1a;卡色-cipchk https://github.com/cipchk cssrem 一个 px 与 rem 单位互转的 VSCode 插件&#xff0c;且支持WXSS微信小程序。 特性…

成集云 | 金蝶EAS与旺店通ERP集成(旺店通主管库存)| 解决方案

源系统成集云目标系统 方案介绍 金蝶EAS是一款全球首款融合TOGAF标准SOA架构的企业管理软件&#xff0c;专门为大中型企业设计&#xff0c;以“创造无边界信息流”为产品设计理念&#xff0c;支持云计算、SOA和动态流程管理的整合技术平台。 旺店通ERP系统是一款专…

API(十)时间相关的SDK

一 时间相关的SDK ① 时间记录的必要性 1、案发现场的时间点2、通过时间判断性能3、时间的不准确性,日志落盘时间 --> 缓冲区导致延迟 ② 使用哪些日期和时间的函数 1、lua 标准时间函数,函数 os.time、os.date 和 os.difftime 提供了所有日期和时间2、在 openresty…

什么是商品价格监控,需要用到API接口嘛

商品价格监控是指通过系统化的方法来追踪、分析和比较商品价格的动态变化&#xff0c;以帮助商家及时获取市场价格信息&#xff0c;做出相应的决策。为了实现这一目标&#xff0c;API接口可以被用来获取商品价格信息。 具体来说&#xff0c;商家可以通过API接口连接到电商平台…

生产制造业厂家固定资产怎么管理

固定资产的管理对于企业的运营效率和盈利能力具有重要影响。然而&#xff0c;传统的固定资产管理方法往往存在许多问题&#xff0c;如资产的低效使用、维护成本高昂以及决策者对资产价值缺乏准确了解等。 因此&#xff0c;我们需要采用一种全新的方式来管理我们的固定资产。本文…

“温莎当下·麦克成风”2023赛季 杭州赛区决赛圆满落幕!

2023年9月16日&#xff0c;“温莎当下麦克成风”2023赛季上海赛区决赛在拱墅区大悦城水秀广场落下帷幕。比赛现场气氛高燃、精彩纷呈&#xff0c;选手们在璀璨的舞台上激情演唱&#xff0c;上演了一场精彩刺激的巅峰争霸赛。经过多轮比拼&#xff0c;最终7号选手方雪莹脱颖而出…

标准防雷接地网和简易地网的制作方法

防雷接地网是整套防雷系统不可缺少的部分&#xff0c;一般是由埋在地下一定深度的多个金属接地极和由导体将这些接地极相互连接组成一网状结构的接地体的总称。它广泛应用在电力、建筑、计算机&#xff0c;工矿企业、通讯等众多行业之中&#xff0c;起着安全防护、屏蔽等作用。…

Spring cloud gateway+apollo=bug?

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 spring cloud 版本 spring cloud: 2021.0.4spring cloud gateway: 3.1.4 背景 最近在配置研究网关的超时时间&#xff0c;有这么一个需求。 服务路由转发接口…

北工大汇编——综合题(2)

题目要求 编写一个比赛得分程序。共有7 个评委&#xff0c;按百分制打分&#xff0c;计分 原则是去掉一个最高分和一个最低分&#xff0c;求平均值。要求&#xff1a; 评委的打分以十进制从键盘输入。成绩以十进制给出&#xff0c;并保留 1位小数。输入输出时屏幕上要有相应提…

口袋参谋:淘宝宝贝秒卡首屏的方法!

​对于新手卖家来说&#xff0c;很多都不太明白&#xff0c;淘宝卡首屏是什么意思&#xff1f;其实卡首屏就是新品前期买家找不到的情况&#xff0c;通过卡首屏让他们快速找到宝贝。 通过卡首屏的方式&#xff0c;给买家账号注入产品标签&#xff0c;让买家进店前就是店铺的精…

「大数据-0.1」虚拟机VMware安装、配置、使用、创建大数据集群教程

目录 一、下载VMware Wworkstation Pro 16 二、安装VMware Wworkstation Pro 16 三、检查与设置VMware的网卡 1. 检查 2. 设置VMware网段 四、在VMware上安装Linux虚拟机 五、对安装好的虚拟机进行设置 1. 打开设置 2. 设置中文 3. 修改字体大小 4. 修改终端字体大小 5. 关闭虚…

【Vue】MVVM模型还没懂嘛

hello&#xff0c;我是小索奇&#xff0c;精心制作的Vue教程持续更新哈&#xff0c;想要学习&巩固&避坑就一起学习叭~ MVVM 模型 Vue虽然没有完全遵循MVVM模型&#xff0c;但Vue的设计也收到了它的启发在文档中也会使用VM&#xff08;ViewModel的缩写&#xff09;这个变…

终于搞清了:SPI、UART、I2C通信的区别与应用!

电子设备之间的通信就像人类之间的交流&#xff0c;双方都需要说相同的语言。在电子产品中&#xff0c;这些语言称为通信协议。 之前有单独地分享了SPI、UART、I2C通信的文章&#xff0c;这篇对它们做一些对比。 串行 VS 并行 电子设备通过发送数据位从而实现相互交谈。位是…