Linux内核之内存管理知识以及伙伴系统

news2024/11/15 14:00:18

内存管理知识以及伙伴系统

  • 一、Linux 内核架构图
  • 二、虚拟内存地址空间布局
    • 2.1、用户空间
    • 2.2、内核空间
    • 2.3、硬件层面
    • 2.4、虚拟地址空间划分
    • 2.5、用户虚拟地址空间布局
    • 2.6、进程的进程描述和内存描述符关系
    • 2.7、内核地址空间布局
  • 三、SMP/NUMA 架构
    • 3.1、SMP
    • 3.2、NUMA
  • 四、伙伴系统及算法
    • 4.1、基本伙伴分配器
    • 4.2、分区伙伴分配器
  • 五、块分配器(Slab/Slub/Slob)
    • 5.1、基本概念
    • 5.2、slab 块分配器原理
    • 5.3、计算 slab 长度及着色
    • 5.4、每处理器数组缓存
    • 5.5、slab 分配器支持 NUMA 体系结构

一、Linux 内核架构图

在这里插入图片描述
在这里插入图片描述

二、虚拟内存地址空间布局

2.1、用户空间

应用程序使用 malloc()申请内存,使用 free()释放内存,malloc()/free() 是 glibc 库的内存分配器 ptmalloc 提供的接口,ptmalloc 使用系统调用 brk/mmap 向内核以页为单位申请内存,然后划分成小内存块分配给用户应用程序。

2.2、内核空间

内核空间的基本功能:虚拟内存管理负责从进程的虚拟地址空间分配虚拟页,sys_brk 用来扩大或收缩堆,sys_mmap 用来在内存映射区域分配虚拟页, sys_munmap 用来释放虚拟页。

页分配器负责分配物理页,当前使用的页分配器是伙伴分配器。内核空间提供把页划分成小内存块分配的块分配器,提供分配内存的接口 kmalloc()和 释放内存接口 kfree()。

块分配器:SLAB/SLUB/SLOB。

2.3、硬件层面

处理器包含一个称为内存管理单元(Memory Management Unit,MMU)的部 件,负责把虚拟地址转换成物理地址。内存管理单元包含一个称为页表缓存 (Translation Lookaside Buffer,TLB)的部件,保存最近使用的页表映射, 避免每次把虚拟地址转换物理地址都需要查询内存中的页表。

2.4、虚拟地址空间划分

以 ARM64 处理器为例:虚拟地址的最大宽度是 48 位。

  • 内核虚拟地址在 64 位地址空间顶部,高 16 位全是 1,范围是[0xFFFF 0000 0000 0000,0xFFFF FFFF FFFF FFFF] 。
  • 用户虚拟地址在 64 位地址空间的底部,高 16 位全是 0, 范围是[0x0000 0000 0000 0000,0x0000 FFFF FFFF FFFF]。
    在这里插入图片描述

在编译 ARM64 架构的 Linux 内核时,可以选择虚拟地址宽度:

  • 选择页长度 4KB,默认虚拟地址宽度为 39 位;
  • 选择页长度 16KB,默认虚拟地址宽度为 47 位;
  • 选择页长度 64KB,默认虚拟地址宽度为 42 位;
  • 选择 48 位虚拟地址。

在 ARM64 架构 linux 内核中,内核虚拟地址用户虚拟地址宽度相同。所有进程共享内核虚拟地址空间,每个进程有独立的用户虚拟地址空间,同一个线程组的用户线程共享用户虚拟地址空间,内核线程没有用户虚拟地址空间。

2.5、用户虚拟地址空间布局

进程的用户虚拟地址空间的起始地址是 0,长度是 TASK_SIZE,由每种处理器架构定义自己的宏 TASK_SIZE。ARM64 架构定义宏 TASK_SIZE 如下所示:

  • 32 位用户空间程序:TASK_SIZE 的值是 TASK_SIZE_32,即 0x10000000,等于 4GB。
  • 64 位用户空间程序:TASK_SIZE 的值是 TASK_SIZE_64,即 2 的 VA_BITS 次方字节,VA_BITS 是编译内核时选择的虚拟地址位数。

(arch/arm64/include/asm/memory.h)

/*
 * PAGE_OFFSET - the virtual address of the start of the linear map, at the
 *               start of the TTBR1 address space.
 * PAGE_END - the end of the linear map, where all other kernel mappings begin.
 * KIMAGE_VADDR - the virtual address of the start of the kernel image.
 * VA_BITS - the maximum number of bits for virtual addresses.
 */
#define VA_BITS			(CONFIG_ARM64_VA_BITS)
#define _PAGE_OFFSET(va)	(-(UL(1) << (va)))
#define PAGE_OFFSET		(_PAGE_OFFSET(VA_BITS))
#define KIMAGE_VADDR		(MODULES_END)
#define BPF_JIT_REGION_START	(KASAN_SHADOW_END)
#define BPF_JIT_REGION_SIZE	(SZ_128M)
#define BPF_JIT_REGION_END	(BPF_JIT_REGION_START + BPF_JIT_REGION_SIZE)
#define MODULES_END		(MODULES_VADDR + MODULES_VSIZE)
#define MODULES_VADDR		(BPF_JIT_REGION_END)
#define MODULES_VSIZE		(SZ_128M)
#define VMEMMAP_START		(-VMEMMAP_SIZE - SZ_2M)
#define PCI_IO_END		(VMEMMAP_START - SZ_2M)
#define PCI_IO_START		(PCI_IO_END - PCI_IO_SIZE)
#define FIXADDR_TOP		(PCI_IO_START - SZ_2M)

#if VA_BITS > 48
#define VA_BITS_MIN		(48)
#else
#define VA_BITS_MIN		(VA_BITS)
#endif

#define _PAGE_END(va)		(-(UL(1) << ((va) - 1)))

#define KERNEL_START		_text
#define KERNEL_END		_end

Linux 内核使用内存描述符 mm_struct 描述进程的用户虚拟地址空间,主要核心成员如下:

// include/linux/mm_types.h

struct mm_struct {
	struct {
		struct vm_area_struct *mmap;//		虚拟内存区域的链表指针
		struct rb_root mm_rb;       // 虚拟内存区域红黑树       
		u64 vmacache_seqnum;                   /* per-thread vmacache */
/*通过在内存映射区域查找一个没有映射的区域*/
#ifdef CONFIG_MMU
		unsigned long (*get_unmapped_area) (struct file *filp,
		unsigned long addr, unsigned long len,
		unsigned long pgoff, unsigned long flags);
#endif
                unsigned long mmap_base;//内存映射区域的起始地址
                // .......
                unsigned long task_size;//表示用户虚拟地址空间的长度大小
               // ......
                pgd_t * pgd;//指向页全局目录(第一级页表)
               // ......
		/**
		 * @mm_users: The number of users including userspace.
		 *
		 * Use mmget()/mmget_not_zero()/mmput() to modify. When this
		 * drops to 0 (i.e. when the task exits and there are no other
		 * temporary reference holders), we also release a reference on
		 * @mm_count (which may then free the &struct mm_struct if
		 * @mm_count also drops to 0).
		 */
		atomic_t mm_users;//共享同一个用户虚拟地址空间的进程数量。

		/**
		 * @mm_count: The number of references to &struct mm_struct
		 * (@mm_users count as 1).
		 *
		 * Use mmgrab()/mmdrop() to modify. When this drops to 0, the
		 * &struct mm_struct is freed.
		 */
		atomic_t mm_count;//引用计数器
                // ......
                spinlock_t arg_lock; /* protect the below fields */
		unsigned long start_code, end_code, start_data, end_data;//代码段、数据段的起始地址和结束地址
		unsigned long start_brk, brk, start_stack;//栈、堆的起始地址和结束地址
		unsigned long arg_start, arg_end, env_start, env_end;//参数字符串、环境变量的起始地址和结束地址
               // ......
                /* Architecture-specific MM context */
		mm_context_t context;//处理器架构的特殊内存管理上下文操作
               // ......
        } __randomize_layout;
        /*
	 * The mm_cpumask needs to be at the end of mm_struct, because it
	 * is dynamically sized based on nr_cpu_ids.
	 */
	unsigned long cpu_bitmap[];
}

mm和mm_user的关系
一个进程的用户虚拟地址空间包括区域:代码段、动态库的代码段、数据段、未初始化数据段、代码段、未初始化代码段、存放在栈底部的环境变量、参数字符串等等。
在这里插入图片描述

2.6、进程的进程描述和内存描述符关系

在这里插入图片描述

2.7、内核地址空间布局

ARM64 处理器架构的内核地址空间布局如下:
在这里插入图片描述
用户空间(256T)、内核空间(256T)、module区域(128M)、PCI I/O区域(16M)、vmalloc区域(123T左右)、vmemmap区域(4096G)。

KASAN影子区域:内核地址的消毒,是一个动态内存错误的检查工具。

三、SMP/NUMA 架构

3.1、SMP

SMP(Symmetric Multi-processing)对称多处理器结构。比如服务器中多个 CPU 对称运行,没有主次和从属关系,CPU 共享相同的物理内存。SMP 也称为一致存储器访问结构(UMA:Uniform Memory Access)。
在这里插入图片描述
SMP架构的处理器是对等的,通过总线连接到同一块物理内存或者同一块IO设备,这样就导致CPU、内存、IO等都是共享的;从而存在一个缺点:扩展性低。CPU的性能和有效性受总线影响,所以,SMP服务器的CPU在两个到四个之间是性能最优的。

3.2、NUMA

NUMA(Non Uniform Memory Access)非统一内存访问。内存访问时间取决于处理器的内存位置。在 NUMA 下,处理器访问它自己的本地存储器的速度比非本地存储器(存储器的地方到另一个处理器之间共享的处理器或存储器)快一些。
在这里插入图片描述
NUMA也存在一些问题:node之间资源交互会慢些,当CPU很多的情况下,它的性能提升并不是很高。

NUMA服务器适合做单点服务器,2到4个node效果是最好的。

NUMA系统提供内存互联,是一种新型动态的分析系统(MP\MMP)。

四、伙伴系统及算法

Linux 内核初始化完毕后,使用页分配器管理物理页,当前使用的页分配器就是伙伴分配器,伙伴分配器的特点是管理算法简单且高效。

4.1、基本伙伴分配器

连续的物理页称为页块(page block),阶(order)是页的数量单位,2的 n 次方个连续页称为 n 阶页块,满足如下条件的两个 n 阶页块称为伙伴(buddy)。

  1. 两个页块是相邻的,即物理地址是连续的;
  2. 页块的第一页的物理面页号必须是 2 的 n 次方的整数倍;
  3. 如果合并(n+1)阶页块,第一页的物理页号必须是 2 的括号(n+1)次方的整数倍。

伙伴分配器分配和释放物理页的数量单位也为阶(order)。

举例:以单页为说明,0 号页和 1 号页是伙伴,2 号页和 3 号页是伙伴;1 号页和2 号页不是伙伴?因为 1 号页和 2 号页合并组成一阶页块,第一页的物理页号不是 2 的整数倍。

4.2、分区伙伴分配器

内存区域的结构体成员 free_area 用来维护空闲页块,数组下标对应页块的除数。结构体 free_area 的成员 free_list 是空闲页块的链表,nr_free 是空闲页块的数量。内存区域的结构体成员 managed_pages 是伙伴分配器管理的物理页的数量。

内存区域数据结构分析如下:

(include/linux/mmzone.h)

struct free_area {
	struct list_head	free_list[MIGRATE_TYPES];
	unsigned long		nr_free;
};

(include/linux/mmzone.h)

struct zone {//内存区域数据结构
	/* Read-mostly fields */

	/* zone watermarks, access with *_wmark_pages(zone) macros */
	unsigned long _watermark[NR_WMARK];//页分配器使用的水线
	unsigned long watermark_boost;

	unsigned long nr_reserved_highatomic;

	/*
	 * We don't know if the memory that we're going to allocate will be
	 * freeable or/and it will be released eventually, so to avoid totally
	 * wasting several GB of ram we must reserve some of the lower zone
	 * memory (otherwise we risk to run OOM on the lower zones despite
	 * there being tons of freeable ram on the higher zones).  This array is
	 * recalculated at runtime if the sysctl_lowmem_reserve_ratio sysctl
	 * changes.
	 */
	long lowmem_reserve[MAX_NR_ZONES];//页分配器使用,当前区域保留多少页不能借给高的区域类型

#ifdef CONFIG_NUMA
	int node;
#endif
	struct pglist_data	*zone_pgdat;
	struct per_cpu_pageset __percpu *pageset;

#ifndef CONFIG_SPARSEMEM
	/*
	 * Flags for a pageblock_nr_pages block. See pageblock-flags.h.
	 * In SPARSEMEM, this map is stored in struct mem_section
	 */
	unsigned long		*pageblock_flags;
#endif /* CONFIG_SPARSEMEM */

	/* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
	unsigned long		zone_start_pfn;

	/*
	 * spanned_pages is the total pages spanned by the zone, including
	 * holes, which is calculated as:
	 * 	spanned_pages = zone_end_pfn - zone_start_pfn;
	 *
	 * present_pages is physical pages existing within the zone, which
	 * is calculated as:
	 *	present_pages = spanned_pages - absent_pages(pages in holes);
	 *
	 * managed_pages is present pages managed by the buddy system, which
	 * is calculated as (reserved_pages includes pages allocated by the
	 * bootmem allocator):
	 *	managed_pages = present_pages - reserved_pages;
	 *
	 * So present_pages may be used by memory hotplug or memory power
	 * management logic to figure out unmanaged pages by checking
	 * (present_pages - managed_pages). And managed_pages should be used
	 * by page allocator and vm scanner to calculate all kinds of watermarks
	 * and thresholds.
	 *
	 * Locking rules:
	 *
	 * zone_start_pfn and spanned_pages are protected by span_seqlock.
	 * It is a seqlock because it has to be read outside of zone->lock,
	 * and it is done in the main allocator path.  But, it is written
	 * quite infrequently.
	 *
	 * The span_seq lock is declared along with zone->lock because it is
	 * frequently read in proximity to zone->lock.  It's good to
	 * give them a chance of being in the same cacheline.
	 *
	 * Write access to present_pages at runtime should be protected by
	 * mem_hotplug_begin/end(). Any reader who can't tolerant drift of
	 * present_pages should get_online_mems() to get a stable value.
	 */
	atomic_long_t		managed_pages;
	unsigned long		spanned_pages;
	unsigned long		present_pages;

	const char		*name;

#ifdef CONFIG_MEMORY_ISOLATION
	/*
	 * Number of isolated pageblock. It is used to solve incorrect
	 * freepage counting problem due to racy retrieving migratetype
	 * of pageblock. Protected by zone->lock.
	 */
	unsigned long		nr_isolate_pageblock;
#endif

#ifdef CONFIG_MEMORY_HOTPLUG
	/* see spanned/present_pages for more description */
	seqlock_t		span_seqlock;
#endif

	int initialized;

	/* Write-intensive fields used from the page allocator */
	ZONE_PADDING(_pad1_)

	/* free areas of different sizes */
	struct free_area	free_area[MAX_ORDER];

	/* zone flags, see below */
	unsigned long		flags;

	/* Primarily protects free_area */
	spinlock_t		lock;

	/* Write-intensive fields used by compaction and vmstats. */
	ZONE_PADDING(_pad2_)

	/*
	 * When free pages are below this point, additional steps are taken
	 * when reading the number of free pages to avoid per-cpu counter
	 * drift allowing watermarks to be breached
	 */
	unsigned long percpu_drift_mark;

#if defined CONFIG_COMPACTION || defined CONFIG_CMA
	/* pfn where compaction free scanner should start */
	unsigned long		compact_cached_free_pfn;
	/* pfn where async and sync compaction migration scanner should start */
	unsigned long		compact_cached_migrate_pfn[2];
	unsigned long		compact_init_migrate_pfn;
	unsigned long		compact_init_free_pfn;
#endif

#ifdef CONFIG_COMPACTION
	/*
	 * On compaction failure, 1<<compact_defer_shift compactions
	 * are skipped before trying again. The number attempted since
	 * last failure is tracked with compact_considered.
	 */
	unsigned int		compact_considered;
	unsigned int		compact_defer_shift;
	int			compact_order_failed;
#endif

#if defined CONFIG_COMPACTION || defined CONFIG_CMA
	/* Set to true when the PG_migrate_skip bits should be cleared */
	bool			compact_blockskip_flush;
#endif

	bool			contiguous;

	ZONE_PADDING(_pad3_)
	/* Zone statistics */
	atomic_long_t		vm_stat[NR_VM_ZONE_STAT_ITEMS];
	atomic_long_t		vm_numa_stat[NR_VM_NUMA_STAT_ITEMS];
} ____cacheline_internodealigned_in_smp;

区域水线数据结构分析:(include/linux/mmzone.h)

enum zone_watermarks {
	WMARK_MIN,
	WMARK_LOW,
	WMARK_HIGH,
	NR_WMARK
};

首选的内存区域在什么情况下从备用区域借用物理页?此问题从区域水线讲解深入理解,每个内存区域有 3 个水线。

  • 高水线(HIGH):如果内存区域的空闲页数大于高水线,说明该内存区域的内存充足;
  • 低水线(LOW):如果内存区域的空闲页数小于低水线,说明该内存区域的内存轻微不足;
  • 最低水线(MIN):如果内存区域空闲页数小于最低水线,说明该内存区域的内存严重不足。

五、块分配器(Slab/Slub/Slob)

5.1、基本概念

Buddy 提供以 page 为单位的内存分配接口,这对内核来说颗粒度还太大,所以需要一种新的机制,将 page 拆分为更小的单位来管理。

Linux 中支持的主要有:slab、slub、slob。其中 slob 分配器的总代码量比较少,但分配速度不是最高效的,所以不是为大型系统设计,适合内存紧张的嵌入式系统。

5.2、slab 块分配器原理

slab 分配器的作用不仅仅是分配小块内存,更重要的作用是针对经常分配和释放的对象充当缓存。slab 分配器的核心思路是:为每种对象类型创建一个内存缓存,每个内存缓存由多个大块组成,一个大块是由一个或多个连续的物理页,每个大块包含多个对象。slab 采用面向对象的思想,基于对象类型管理内存,每种对象被划分为一类,比如进程描述符 task_struct 是一个类,每个进程描述符实例是一个对象。如下图所示为内存缓存的组成结构:
在这里插入图片描述
slab 分配器在某些情况下表现不太优先,所以 Linux 内核提供两个改进的块分配器。

  • 在配备大量物理内存的大型计算机上,slab分配器的管理数据结构的内存开销比较大,所以设计了slub分配器。
  • 在小内存的嵌入式设备上,slab 分配器的代码过多、相当复杂,所以设计一个精简 slob 分配器。

目前 slub 分配器已成为默认的块分配器。

5.3、计算 slab 长度及着色

(1)计算 slab:函数 calculate_slab_order 负责计算 slab 长度,从 0 阶到kmalloc()函数支持最大除数 KMALLOC_MAX_ORDER。

(mm/slab.c)

/**
 * calculate_slab_order - calculate size (page order) of slabs
 * @cachep: pointer to the cache that is being created
 * @size: size of objects to be created in this cache.
 * @flags: slab allocation flags
 *
 * Also calculates the number of objects per slab.
 *
 * This could be made much more intelligent.  For now, try to avoid using
 * high order pages for slabs.  When the gfp() functions are more friendly
 * towards high-order requests, this should be changed.
 *
 * Return: number of left-over bytes in a slab
 */
static size_t calculate_slab_order(struct kmem_cache *cachep,
				size_t size, slab_flags_t flags)
{
	size_t left_over = 0;
	int gfporder;

	for (gfporder = 0; gfporder <= KMALLOC_MAX_ORDER; gfporder++) {
		unsigned int num;
		size_t remainder;

		num = cache_estimate(gfporder, size, flags, &remainder);
		if (!num)
			continue;

		/* Can't handle number of objects more than SLAB_OBJ_MAX_NUM */
		if (num > SLAB_OBJ_MAX_NUM)
			break;

		if (flags & CFLGS_OFF_SLAB) {
			struct kmem_cache *freelist_cache;
			size_t freelist_size;

			freelist_size = num * sizeof(freelist_idx_t);
			freelist_cache = kmalloc_slab(freelist_size, 0u);
			if (!freelist_cache)
				continue;

			/*
			 * Needed to avoid possible looping condition
			 * in cache_grow_begin()
			 */
			if (OFF_SLAB(freelist_cache))
				continue;

			/* check if off slab has enough benefit */
			if (freelist_cache->size > cachep->size / 2)
				continue;
		}

		/* Found something acceptable - save it away */
		cachep->num = num;
		cachep->gfporder = gfporder;
		left_over = remainder;

		/*
		 * A VFS-reclaimable slab tends to have most allocations
		 * as GFP_NOFS and we really don't want to have to be allocating
		 * higher-order pages when we are unable to shrink dcache.
		 */
		if (flags & SLAB_RECLAIM_ACCOUNT)
			break;

		/*
		 * Large number of objects is good, but very large slabs are
		 * currently bad for the gfp()s.
		 */
		if (gfporder >= slab_max_order)
			break;

		/*
		 * Acceptable internal fragmentation?
		 */
		if (left_over * 8 <= (PAGE_SIZE << gfporder))
			break;
	}
	return left_over;
}

(2)着色:
slab 是一个或多个连续的物理页,起始地址总是页长度的整数倍,不同slab 中相同偏移的位置在处理器一级缓存中的索引相同。如果 slab 的剩余部分的长度超过一级缓存行的长度,剩余部分对应的一级缓存行没有被利用;如果对象的填充字节的长度超过一级缓存行的长度,填充字节对应的一级缓存行没有被利用。这两种情况导致处理器的某些缓存行被过度使用,另一些缓存行很少使用。

5.4、每处理器数组缓存

内存缓存为每个处理器创建一个数组缓存(结构体 array_cache)。释放 对象时,把对象存放到当前处理器对应的数组缓存中;分配对象的时候,先从当前处理器的数组缓存分配对象,采用后进先出(Last In First Out,LIFO) 的原则,这种做可以提高性能。
在这里插入图片描述

// include/linux/slab_def.h

struct kmem_cache {
	struct array_cache __percpu *cpu_cache;

/* 1) Cache tunables. Protected by slab_mutex */
	unsigned int batchcount;
	unsigned int limit;
	unsigned int shared;

	unsigned int size;
	struct reciprocal_value reciprocal_buffer_size;
/* 2) touched by every alloc & free from the backend */

	slab_flags_t flags;		/* constant flags */
	unsigned int num;		/* # of objs per slab */

/* 3) cache_grow/shrink */
	/* order of pgs per slab (2^n) */
	unsigned int gfporder;

	/* force GFP flags, e.g. GFP_DMA */
	gfp_t allocflags;

	size_t colour;			/* cache colouring range */
	unsigned int colour_off;	/* colour offset */
	struct kmem_cache *freelist_cache;
	unsigned int freelist_size;

	/* constructor func */
	void (*ctor)(void *obj);

/* 4) cache creation/removal */
	const char *name;
	struct list_head list;
	int refcount;
	int object_size;
	int align;

/* 5) statistics */
#ifdef CONFIG_DEBUG_SLAB
	unsigned long num_active;
	unsigned long num_allocations;
	unsigned long high_mark;
	unsigned long grown;
	unsigned long reaped;
	unsigned long errors;
	unsigned long max_freeable;
	unsigned long node_allocs;
	unsigned long node_frees;
	unsigned long node_overflow;
	atomic_t allochit;
	atomic_t allocmiss;
	atomic_t freehit;
	atomic_t freemiss;

	/*
	 * If debugging is enabled, then the allocator can add additional
	 * fields and/or padding to every object. 'size' contains the total
	 * object size including these internal fields, while 'obj_offset'
	 * and 'object_size' contain the offset to the user object and its
	 * size.
	 */
	int obj_offset;
#endif /* CONFIG_DEBUG_SLAB */

#ifdef CONFIG_MEMCG
	struct memcg_cache_params memcg_params;
#endif
#ifdef CONFIG_KASAN
	struct kasan_cache kasan_info;
#endif

#ifdef CONFIG_SLAB_FREELIST_RANDOM
	unsigned int *random_seq;
#endif

	unsigned int useroffset;	/* Usercopy region offset */
	unsigned int usersize;		/* Usercopy region size */

	struct kmem_cache_node *node[MAX_NUMNODES];
};

5.5、slab 分配器支持 NUMA 体系结构

内存缓存针对每个内存节点创建一个 kmem_cache_node 实例视图如下:

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

传输线的物理基础(四):传输线的特性阻抗

特性阻抗和控制阻抗对于一条均匀的线&#xff0c;无论我们选择看哪里&#xff0c;我们都会看到沿线传播时相同的瞬时阻抗。有一个表征传输线的瞬时阻抗&#xff0c;我们给它起了一个特殊的名字&#xff1a;特性阻抗。有一个瞬时阻抗是均匀传输线的特征。我们将这种恒定的瞬时阻…

RZ/G2L工业核心板U盘读写速率测试

1. 测试对象HD-G2L-IOT基于HD-G2L-CORE工业级核心板设计&#xff0c;双路千兆网口、双路CAN-bus、2路RS-232、2路RS-485、DSI、LCD、4G/5G、WiFi、CSI摄像头接口等&#xff0c;接口丰富&#xff0c;适用于工业现场应用需求&#xff0c;亦方便用户评估核心板及CPU的性能。HD-G2L…

idm如何下载种子文件和磁力链接 idm如何下载torrent

采用分段式下载技术并支持断点续传的idm下载加速器&#xff0c;几乎可以胜任所有的下载任务。由于该软件强大的下载能力和仅为10MB的小巧体积&#xff0c;idm被来自全球的用户亲切地称为天花板级的下载软件。那么有关idm如何下载种子文件和磁力链接&#xff0c;idm如何下载torr…

基于vivado(语言Verilog)的FPGA学习(1)——了解viviado面板和编译过程

基于vivado&#xff08;语言Verilog&#xff09;的FPGA学习&#xff08;1&#xff09;——了解程序面板和编译过程 每日废话&#xff1a;最近找实习略微一些焦虑&#xff0c;不想找软件开发&#xff0c;虽然有些C和python基础&#xff08;之前上课学的&#xff09;&#xff0c;…

编码技巧——Redis Pipeline

本文介绍Redis pipeline相关的知识点及代码示例&#xff0c;包括Redis客户端-服务端的一次完整的网络请求、pipeline与client执行多命令的区别、pipeline与Redis"事务"、pipeline的使用代码示例&#xff1b; pipeline与client执行多命令的区别 Redis是一种基于客户…

如何挖掘专利创新点?

“无意中发现了一个巨牛的人工智能教程&#xff0c;忍不住分享一下给大家。教程不仅是零基础&#xff0c;通俗易懂&#xff0c;而且非常风趣幽默&#xff0c;像看小说一样&#xff01;觉得太牛了&#xff0c;所以分享给大家。点这里可以跳转到教程。” 对于广大的软件工程师来说…

W806|CKLINK LITE|ICE调试|HardPoint|elf模板|CSDK|Debug|学习(4):CKLINK调试W806

目录 一、硬件连接 接线方式 错误提示 二、调试前准备 正常识别状态 wm_tool.exe缺失错误​ 三、flash配置 增加W806模板 compiler选项卡 Debug选项卡 ICE设置 正常连接信息 四、调试工程 添加硬断点 断点配置 仿真调试 下载固件 参考&#xff1a; 《手把手教…

《MySQL系列-InnoDB引擎28》表-约束详细介绍

约束 1 数据完整性 关系型数据库系统和文件系统的一个不同点是&#xff0c;关系数据库本身能保证存储数据的完整性&#xff0c;不需要应用程序的控制&#xff0c;而文件系统一般需要在程序端进行控制。当前几乎所有的关系型数据库都提供约束(constraint)机制&#xff0c;该机制…

群智能优化计算中的混沌映射

经实验证明&#xff0c;采用混沌映射产生随机数的适应度函数值有明显提高&#xff0c;用混沌映射取代常规的均匀分布的随机数发生器可以得到更好的结果&#xff0c;特别是搜索空间中有许多局部解时&#xff0c;更容易搜索到全局最优解&#xff0c;利用混沌序列进行种群初始化、…

基于Qt WebEngine 的Web仪器面板GUI程控技术

随着IIoT的发展&#xff0c;很多工业仪器也具备了远程管理的GUI。与早期使用串口进行命令交互不同&#xff0c;这些GUI可以直接在远程呈现数据。 作为希望对仪器、软件进行二次开发的小公司来说&#xff0c;会遇到GUI人工操作转自动化的需求。在无法通过串口等传统接口进行自动…

nextjs开发 + vercel 部署 ssr ssg

前言 最近想实践下ssr 就打算用nextjs 做一个人博客 &#xff0c; vercel 部署 提供免费域名&#xff0c;来学习实践下ssr ssg nextjs 一个轻量级的react服务端渲染框架 vercel 由 Next.js 的创建者制作 支持nextjs 部署 免费静态网站托管 初始化项目 npx create-next-app p…

【Linux】目录结构

Linux世界里&#xff0c;一切皆文件。 /bin&#xff1a;是Binary的缩写&#xff0c;这个目录存放着最经常使用的命令。&#xff08;常用&#xff09; /sbin&#xff1a;s就是Super User的意思&#xff0c;这里存放的是系统管理员使用的系统管理程序。 /home&#xff1a;存放普…

关于Pytorch中的张量学习

关于Pytorch中的张量学习 张量的概念和创建 张量的概念 Tensor是pytorch中非常重要且常见的数据结构&#xff0c;相较于numpy数组&#xff0c;Tensor能加载到GPU中&#xff0c;从而有效地利用GPU进行加速计算。但是普通的Tensor对于构建神经网络还远远不够&#xff0c;我们需…

实力加持!RestCloud完成多方国产化适配,携手共建信创生态

近年来&#xff0c;随着数字化建设进入深水区&#xff0c;企事业单位对信息安全重视程度与日俱增&#xff0c;核心技术自主可控已成为时代呼唤&#xff0c;国产化浪潮日益汹涌澎湃。近日&#xff0c;RestCloud在国产化方面取得新进展&#xff0c;完成了全部产品线信创环境的多方…

系统重装漏洞

zzcms系统重装漏洞 一、配置zzcms环境 1. 使用小皮搭建zzcms框架 2. 安装zzcms 按照下面的操作进行,傻瓜式操作即可 3. 打开网站 二、漏洞利用 在访问install目录的默认文件后,会出现zzcms安装向导 http://www.zzcms.com/install/index.php 但是会显示 “安装向导…

MQTT协议-发布消息(客户端向服务器发送)

MQTT协议-发布消息&#xff08;客户端向服务器发送&#xff09; 发布消息报文组成&#xff1a;https://blog.csdn.net/weixin_46251230/article/details/129414158 在分析完服务器下发到客户端的报文后&#xff0c;就可以参考JSON格式的有效载荷&#xff0c;将温湿度的值改为…

Linux发行版的backport

遇到一个问题,简要记录如下: base on ubuntu18.06 4.15内核,这版内核不支持一款intel的集成网卡,追踪内核代码的提交历史才发现,这款网卡是从linux-4.20才开始支持的,系统自带的这个Kernel版本不支持。 如果不允许升级内核,面对这种问题,社区的做法是把新内核的特性cher…

顺序表【数据结构】

文章目录:star2:1. 顺序表概念:star2:2. 框架3. 基本功能3.1 头文件:star:3.2 初始化:star:3.3 扩容:star:3.4 打印:star:3.5 尾插:star:3.6 头插:star:3.7 尾删:star:3.8 头删:star:3.9 指定插入:star:3.10 指定删除:star:3.11 查找:star2:3.12 注意事项4. 顺序表的缺点&#…

云原生安全2.X 进化论系列|云原生安全2.X未来展望(4)

随着云计算技术的蓬勃发展&#xff0c;传统上云实践中的应用升级缓慢、架构臃肿、无法快速迭代等“痛点”日益明显。能够有效解决这些“痛点”的云原生技术正蓬勃发展&#xff0c;成为赋能业务创新的重要推动力&#xff0c;并已经应用到企业核心业务。然而&#xff0c;云原生技…

Git学习笔记(六)-标签管理

发布一个版本时&#xff0c;我们通常先在版本库中打一个标签&#xff08;tag&#xff09;&#xff0c;这样&#xff0c;就唯一确定了打标签时刻的版本。将来无论什么时候&#xff0c;取某个标签的版本&#xff0c;就是把那个打标签的时刻的历史版本取出来。所以&#xff0c;标签…