当前位置: 首页 > news >正文

linux内存页块划分及位图存储机制

page_alloc.c - mm/page_alloc.c - Linux source code v5.4.285 - Bootlin Elixir Cross Referencer

一. 什么是页块(Pageblock)?

  • 定义:页块是物理内存中的一个连续区域,由 2^pageblock_order 个物理页(Page)组成。

  • 作用:页块是内存碎片管理的最小单位,用于跟踪内存区域的 迁移类型(Migratetype)(如可移动、不可移动等),优化内存分配和碎片整理。


1.1. pageblock_order 的默认值

  • 常规配置

    #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE#define pageblock_order HUGETLB_PAGE_ORDER
    #else#define pageblock_order (MAX_ORDER - 1)
    #endif
     
    • 默认情况:若未启用巨型页(HugeTLB)的动态大小配置,pageblock_order 通常设置为 MAX_ORDER - 1

    • MAX_ORDER:伙伴系统的最大分配阶数,通常为 11(对应 2^10 = 1024 页,即 4MB,假设页大小为 4KB)。

  • 结果

    • 默认页块大小为 2^(MAX_ORDER-1) 页(例如 MAX_ORDER=11 时,页块为 2^10 = 1024 页 = 4MB)。

    • 每个页块在全局位图 pageblock_flags 中占用若干位(如3位用于迁移类型)。


1.2. 为什么选择 MAX_ORDER - 1

设计目标
  • 对齐伙伴系统:确保页块大小与伙伴系统的最大连续内存块(MAX_ORDER)对齐,避免跨页块分配。

  • 减少碎片:较大的页块能更高效地隔离不可移动内存(如内核对象),减少长期内存碎片。

  • 迁移类型管理:每个页块独立维护迁移类型,方便内存碎片整理时批量移动页面。

权衡
  • 内存粒度:页块越大,管理更粗粒度,可能浪费内存;页块越小,管理更细粒度,但元数据开销增加。

  • 性能:较大的页块减少位图操作次数,提高效率。

二、什么是页块位图?

1. ​核心作用与背景

pageblock_flags 是 Linux 内存管理中的一个关键数据结构,主要用于跟踪和管理 ​内存块(pageblock)​ 的特性。通过 pageblock_flags,内核可以高效地记录每个内存块的属性,例如迁移类型、分配状态等,从而优化内存分配与回收策略。

2. ​数据结构与存储方式
  • 存储位置pageblock_flags 以位图(bitmap)形式存储在 struct zone 结构体中(字段 unsigned long *pageblock_flags),每个内存块对应位图中的若干比特位
    // https://elixir.bootlin.com/linux/v5.4.285/source/include/linux/mmzone.h#L448struct zone {
    #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 */
    }

    单个 pageblock_flags 元素可表示的页块和页的数量为:

    32位系统:32/4=8 个页块=8*1024页。

    64位系统:64/4=16 个页块=16*1024页。

  • 位图管理:每个内存块的标志位由 NR_PAGEBLOCK_BITS 定义,用于存储以下信息:
    • 迁移类型​(如 MIGRATE_UNMOVABLEMIGRATE_MOVABLE 等)。
    • 内存块的其他状态(如是否跳过内存碎片整理等)
      #define PB_migratetype_bits 3
      /* Bit indices that affect a whole block of pages */
      enum pageblock_bits {PB_migrate,PB_migrate_end = PB_migrate + PB_migratetype_bits - 1,/* 3 bits required for migrate types */PB_migrate_skip,/* 1位标记是否跳过压缩(PB_migrate_skip),避免重复处理低效内存块 *//** Assume the bits will always align on a word. If this assumption* changes then get/set pageblock needs updating.*/NR_PAGEBLOCK_BITS
      };

3. ​初始化


free_area_init_core -> setup_usemap

static void __ref setup_usemap(struct pglist_data *pgdat,struct zone *zone,unsigned long zone_start_pfn,unsigned long zonesize)
{unsigned long usemapsize = usemap_size(zone_start_pfn, zonesize);zone->pageblock_flags = NULL;if (usemapsize) {zone->pageblock_flags =memblock_alloc_node(usemapsize, SMP_CACHE_BYTES,pgdat->node_id);if (!zone->pageblock_flags)panic("Failed to allocate %ld bytes for zone %s pageblock flags on node %d\n",usemapsize, zone->name, pgdat->node_id);}
}

setup_usemap 的作用是为内存管理区(Zone)分配并初始化 pageblock_flags 位图,该位图用于跟踪每个内存块(Pageblock)的迁移类型(Migratetype)和其他状态。


参数说明

  • struct pglist_data *pgdat: 指向 NUMA 节点的 pglist_data 结构,描述节点的内存布局。
  • struct zone *zone: 目标内存管理区(如 ZONE_NORMALZONE_DMA)。
  • unsigned long zone_start_pfn: 该 Zone 的起始物理页帧号(Page Frame Number)。
  • unsigned long zonesize: 该 Zone 的总页数。

代码逻辑分解

1. 计算 pageblock_flags 位图大小

#define PB_migratetype_bits 3
/* Bit indices that affect a whole block of pages */
enum pageblock_bits {PB_migrate,PB_migrate_end = PB_migrate + PB_migratetype_bits - 1,/* 3 bits required for migrate types */PB_migrate_skip,/* 1位标记是否跳过压缩(PB_migrate_skip),避免重复处理低效内存块 *//** Assume the bits will always align on a word. If this assumption* changes then get/set pageblock needs updating.*/NR_PAGEBLOCK_BITS
};#define pageblock_nr_pages	(1UL << pageblock_order)static unsigned long __init usemap_size(unsigned long zone_start_pfn, unsigned long zonesize)
{unsigned long usemapsize;zonesize += zone_start_pfn & (pageblock_nr_pages-1);       // 步骤1:对齐修正usemapsize = roundup(zonesize, pageblock_nr_pages);        // 步骤2:向上对齐到pageblock整数倍usemapsize = usemapsize >> pageblock_order;                // 步骤3:计算pageblock数量usemapsize *= NR_PAGEBLOCK_BITS;                           // 步骤4:总位数 = 块数 × 4位usemapsize = roundup(usemapsize, 8 * sizeof(unsigned long));// 步骤5:位对齐到unsigned longreturn usemapsize / 8;                                     // 步骤6:转换为字节
}
  • ​**usemap_size()**: 计算位图所需内存大小(单位:字节)。
    • 参数:根据 Zone 的起始页帧(zone_start_pfn)和总页数(zonesize)。
    • 内部逻辑:
      举例:某一个zone的start pfn = 0X1234;end pfn =  0X3600;zonesize = 0X23CC
      操作目的结果
      计算对齐修正值处理Zone起始地址未按pageblock对齐的情况(如Zone起始于一个pageblock中间),修正总页数以包含不完整的起始pageblock修正值:zone_start_pfn & (pageblock_nr_pages-1)=0x234
      zonesize += zone_start_pfn & (pageblock_nr_pages-1)=0x23CC+0x234=0x2600
      向上取整对齐确保总页数是pageblock大小的整数倍(例如:1024页的倍数),避免部分pageblock无法被位图覆盖usemapsize  = roundup(zonesize, pageblock_nr_pages) = roundup(0x2600, 1024)  = 0x2800页
      计算pageblock数量右移pageblock_order位(等价于除以pageblock_nr_pages),得到Zone内完整的pageblock数量usemapsize = usemapsize >> pageblock_order; =   0x2800 >> 10 = 10
      计算总位数每个pageblock需要NR_PAGEBLOCK_BITS(4位)来存储状态,总位数 = pageblock数量 × 440
      最终位图大小(字节)​​总位数 / 8(1字节=8位)40 / 8 = 5。(32bit系统上,需要两个pageblock_flags元素)

 


2. 分配 pageblock_flags 内存

if (usemapsize) {zone->pageblock_flags = memblock_alloc_node(usemapsize, SMP_CACHE_BYTES, pgdat->node_id);// ...
}
  • 条件判断:仅在 usemapsize > 0 时分配内存(Zone 包含至少一个完整内存块)。
  • 分配函数memblock_alloc_node
    • 用途: 在内核启动早期(伙伴系统未初始化时),从 memblock 分配器分配内存。
    • 参数:
      • usemapsize: 分配的字节数。
      • SMP_CACHE_BYTES: 对齐到缓存行(通常 64 字节),避免伪共享(False Sharing)。
      • pgdat->node_id: 在指定 NUMA 节点上分配内存,确保 NUMA 亲和性。
  • 结果zone->pageblock_flags 指向分配的位图内存。

三. 实际应用场景

3.1、内存碎片整理(Memory Compaction)

碎片整理器根据页块的迁移类型,将可移动页面(如用户态数据)迁移到其他页块,腾出连续内存。页块大小决定了迁移操作的最小单位。

3.1.1、设置迁移类型set_pageblock_migratetype(struct page *page, int migratetype),用于在页释放时将其所属内存块的迁移类型标记为正确值

#define PB_migratetype_bits 3
/* Bit indices that affect a whole block of pages */
enum pageblock_bits {PB_migrate,PB_migrate_end = PB_migrate + PB_migratetype_bits - 1,/* 3 bits required for migrate types */PB_migrate_skip,/* If set the block is skipped by compaction *//** Assume the bits will always align on a word. If this assumption* changes then get/set pageblock needs updating.*/NR_PAGEBLOCK_BITS
};#define set_pageblock_flags_group(page, flags, start_bitidx, end_bitidx) \set_pfnblock_flags_mask(page, flags, page_to_pfn(page),		\end_bitidx,					\(1 << (end_bitidx - start_bitidx + 1)) - 1)void set_pageblock_migratetype(struct page *page, int migratetype)
{if (unlikely(page_group_by_mobility_disabled &&migratetype < MIGRATE_PCPTYPES))migratetype = MIGRATE_UNMOVABLE;set_pageblock_flags_group(page, (unsigned long)migratetype,PB_migrate, PB_migrate_end);
}/*** set_pfnblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages* @page: The page within the block of interest* @flags: The flags to set* @pfn: The target page frame number* @end_bitidx: The last bit of interest* @mask: mask of bits that the caller is interested in*/
void set_pfnblock_flags_mask(struct page *page, unsigned long flags,unsigned long pfn,unsigned long end_bitidx,unsigned long mask)
{unsigned long *bitmap;unsigned long bitidx, word_bitidx;unsigned long old_word, word;BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4);BUILD_BUG_ON(MIGRATE_TYPES > (1 << PB_migratetype_bits));// 获取目标页块对应的位图指针及位偏移bitmap = get_pageblock_bitmap(page, pfn); //page_zone(page)->pageblock_flagsbitidx = pfn_to_bitidx(page, pfn);// 计算位图中的具体位置(原子操作)word_bitidx = bitidx / BITS_PER_LONG;bitidx &= (BITS_PER_LONG-1);VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page);// 位操作:对齐掩码和标志值bitidx += end_bitidx;mask <<= (BITS_PER_LONG - bitidx - 1);flags <<= (BITS_PER_LONG - bitidx - 1);// 原子更新位图word = READ_ONCE(bitmap[word_bitidx]);for (;;) {old_word = cmpxchg(&bitmap[word_bitidx], word, (word & ~mask) | flags);if (word == old_word)break;word = old_word;}
}static inline int pfn_to_bitidx(struct page *page, unsigned long pfn)
{// 步骤1:计算对齐后的Zone起始PFN,并调整pfn为相对于该起始的偏移pfn = pfn - round_down(page_zone(page)->zone_start_pfn, pageblock_nr_pages);// 步骤2:将偏移转换为内存块索引,再乘以每块占用的位数,得到位索引return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
}

迁移特性开关检查
page_group_by_mobility_disabled全局标志(由系统内存状态决定)若为真,表示禁用按迁移类型分组。此时强制将基础迁移类型(如MIGRATE_MOVABLE)设为MIGRATE_UNMOVABLE,避免碎片整理操作。

生成掩码:

(1 << (end_bitidx - start_bitidx + 1)) - 1

计算start_bitidxend_bitidx的位宽(如3位),生成掩码0b111

pfn_to_bitidx:将物理页帧号(PFN)转换为对应内存块(Pageblock)在位图(pageblock_flags)中的起始位索引

示例:
  • 参数
    • zone_start_pfn = 0x1234(未对齐到内存块大小)。
    • pageblock_nr_pages = 1024
    • pfn = 0x1500(目标页 PFN)。
  • 计算过程
    1. 对齐 Zone 起始 PFN
      round_down(0x1234, 1024) = 0x1000
    2. PFN 偏移
      0x1500 - 0x1000 = 0x500
    3. 内存块索引
      0x500 >> 10 = 1(第 1 个内存块)。
    4. 位索引
      1 * 4 = 4
  • 结果
    该页位于第 1 个内存块,其状态位在位图的第 4 位。

3.1.2、​获取迁移类型get_pageblock_migratetype(struct page *page),从页的元数据中提取所属内存块的迁移类型

3.1.3、​初始化与校验:在系统启动时,内核会检查每个迁移类型的内存块是否达到最小数量(pageblock_nr_pages),以决定是否启用迁移优化特性

3.2、连续内存分配器(CMA)
  • CMA 预留的连续内存以页块为单位管理,pageblock_order 影响 CMA 区域的最小粒度。

3.3、巨型页(HugeTLB)
  • 若启用动态巨型页大小(CONFIG_HUGETLB_PAGE_SIZE_VARIABLE),pageblock_order 可能与巨型页大小对齐。

3.4、内存热插拔
  • 动态调整内存区域时,通过 pageblock_flags 快速定位可迁移或可回收的内存块

page_alloc.c - mm/page_alloc.c - Linux source code v5.4.285 - Bootlin Elixir Cross Referencer

page_alloc.c - mm/page_alloc.c - Linux source code v5.4.285 - Bootlin Elixir Cross Referencer

相关文章:

linux内存页块划分及位图存储机制

page_alloc.c - mm/page_alloc.c - Linux source code v5.4.285 - Bootlin Elixir Cross Referencer 一. 什么是页块&#xff08;Pageblock&#xff09;&#xff1f; 定义&#xff1a;页块是物理内存中的一个连续区域&#xff0c;由 2^pageblock_order 个物理页&#xff08;Pag…...

Vue 文件下载功能的跨域处理与前后端实现详解

在 Web 应用开发中&#xff0c;文件下载功能是常见需求。但由于跨域限制和认证机制的复杂性&#xff0c;实际开发中常遇到下载失败或权限错误等问题。本文将结合 Vue 前端和 Spring Boot 后端&#xff0c;详细介绍文件下载功能的实现与跨域问题的解决方案。 一、问题背景 在某…...

boost::beast websocket 实例

环境&#xff1a;ubuntu 1. 安装boost sudo apt install -y libboost-all-dev 2. Server端 #include <boost/asio.hpp> #include <boost/beast.hpp> #include <iostream> #include <thread>namespace beast boost::beast; // 从 Boost.Beast 中导…...

复试难度,西电卓越工程师学院(杭研院)考研录取情况

01、卓越工程师学院各个方向 02、24卓越工程师学院&#xff08;杭研院&#xff09;近三年复试分数线对比 PS&#xff1a;卓越工程师学院分为广研院、杭研院 分别有新一代电子信息技术、通信工程、集成电路工程、计算机技术、光学信息工程、网络信息安全、机械&#xff0c;这些…...

Rabbitmq--延迟消息

13.延迟消息 延迟消息&#xff1a;生产者发送消息时指定一个时间&#xff0c;消费者不会立刻收到消息&#xff0c;而是在指定时间之后才会收到消息 延迟任务&#xff1a;一定时间之后才会执行的任务 1.死信交换机 当一个队列中的某条消息满足下列情况之一时&#xff0c;就会…...

cocos creator使用mesh修改图片为圆形,减少使用mask,j减少drawcall,优化性能

cocos creator版本2.4.11 一个mask占用drawcall 3个以上&#xff0c;针对游戏中技能图标&#xff0c;cd,以及多玩家头像&#xff0c;是有很大优化空间 1.上代码&#xff0c;只适合单独图片的&#xff0c;不适合在图集中的图片 const { ccclass, property } cc._decorator;c…...

C++ Qt开发成长之路,从入门到企业级实战项目,保姆级学习路线

Qt 介绍 Qt是一个跨平台的C图形用户界面应用程序开发框架&#xff0c;最初由挪威的Trolltech公司开发&#xff0c;后来被诺基亚收购&#xff0c;现在由Qt公司维护。它提供了丰富的工具和类库&#xff0c;使开发者能够轻松地创建各种类型的应用程序&#xff0c;包括桌面应用、移…...

JavaWeb后端基础(7)AOP

AOP是Spring框架的核心之一&#xff0c;那什么是AOP&#xff1f;AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实说白了&#xff0c;面向切面编程就是面向特定方法编程。AOP是一种思想&#xff0c;而在Spring框…...

Uniapp实现地图获取定位功能

摘要&#xff1a;本文将手把手教你如何在Uniapp项目中集成地图功能、实现定位获取&#xff0c;并解决微信小程序、APP、H5三端的兼容性问题&#x1f680;&#x1f680;&#x1f680; 一、环境准备 地图平台选择 微信小程序&#xff1a;腾讯地图&#xff08;强制使用&#xff09…...

批量将 Excel 转换 PDF/Word/CSV以及图片等其它格式

Excel 格式转换是我们工作过程当中非常常见的一个需求&#xff0c;我们通常需要将 Excel 转换为其他各种各样的格式。比如将 Excel 转换为 PDF、比如说将 Excel 转换为 Word、再比如说将 Excel文档转换为图片等等。 这些操作对我们来讲都不难&#xff0c;因为我们通过 Office 都…...

Flutter:StatelessWidget vs StatefulWidget 深度解析

目录 1. 引言 2. StatelessWidget&#xff08;无状态组件&#xff09; 2.1 定义与特点 2.2 代码示例 3. StatefulWidget&#xff08;有状态组件&#xff09; 3.1 定义与特点 3.2 代码示例 4. StatelessWidget vs StatefulWidget 对比 5. StatefulWidget 生命周期 5.1…...

Stream流学习

Stream流 把数据放进stream流水线&#xff0c;对数据进行一系列操作&#xff08;中间方法&#xff09;&#xff0c;最后封装&#xff08;终结方法&#xff09;。 Stream.of()允许传入任何参数 常见中间方法 可以对数据进行链式&#xff08;流水线&#xff09;操作&#xff0c;但…...

多视图几何--恢复相机位姿/内参的几种方法

恢复相机位姿的几种方法 1分解投影矩阵 1.1投影矩阵分解为相机内外参矩阵的完整解析 投影矩阵&#xff08;Projection Matrix&#xff09;是计算机视觉中将三维世界点映射到二维像素坐标的核心工具&#xff0c;其本质是相机内参矩阵&#xff08;Intrinsic Matrix&#xff09…...

[数据结构]堆详解

目录 一、堆的概念及结构 二、堆的实现 1.堆的定义 2堆的初始化 3堆的插入 ​编辑 4.堆的删除 5堆的其他操作 6代码合集 三、堆的应用 &#xff08;一&#xff09;堆排序&#xff08;重点&#xff09; &#xff08;二&#xff09;TOP-K问题 一、堆的概念及结构 堆的…...

领域驱动设计(DDD)与MVC架构:理念对比与架构选择

领域驱动设计&#xff08;DDD&#xff09;与MVC架构&#xff1a;理念对比与架构选择 一、架构之争的本质&#xff1a;业务复杂度驱动技术演进 在软件开发领域&#xff0c;没有银弹式的完美架构&#xff0c;只有适合当前业务场景的合理选择。MVC与DDD的区别本质上是业务复杂度与…...

牛客周赛:84:B:JAVA

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 import java.util.ArrayList; import java.util.Arrays; import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner scanner new Scanner(S…...

【理想解法学习笔记】

目录 理想解法原理简介算法步骤属性值规范化方法代码示例 理想解法 原理简介 TOPSIS(Technique for Order Preference by Simi larity to IdealSolution)法是一种逼近理想解的排序方法。其基本的处理思路是&#xff1a;首先建立初始化决策矩阵&#xff0c;而后基于规范化后的初…...

CI/CD—Jenkins配置一次完整的jar自动化发布流程

背景&#xff1a; 实现设想&#xff1a; 要创建自动化发布&#xff0c;需要准备一台测试服务器提前安装好java运行所需的环境&#xff0c;JDK版本最好和Windows开发机器上的版本一致&#xff0c;在Jenkins上配置将构建好的jar上传到测试服务器上&#xff0c;测试服务器自动启动…...

Magento2根据图片文件包导入产品图片

图片包给的图片文件是子产品的图片&#xff0c;如下图&#xff1a;A104255是主产品的sku <?php/*** 根据图片包导入产品图片&#xff0c;包含子产品和主产品* 子产品是作为主图&#xff0c;主产品是作为附加图片*/use Magento\Framework\App\Bootstrap;include(../app/boot…...

从零开始的python学习(五)P71+P72+P73+P74

本文章记录观看B站python教程学习笔记和实践感悟&#xff0c;视频链接&#xff1a;【花了2万多买的Python教程全套&#xff0c;现在分享给大家&#xff0c;入门到精通(Python全栈开发教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…...

OpenHarmony5.0分布式系统源码实现分析—软总线

一、引言 OpenHarmony 作为一款面向万物互联的操作系统&#xff0c;其分布式软总线&#xff08;Distributed SoftBus&#xff09;是实现设备间高效通信和协同的核心技术之一。分布式软总线通过构建一个虚拟的总线网络&#xff0c;使得不同设备能够无缝连接、通信和协同工作。本…...

基于SpringBoot实现旅游酒店平台功能六

一、前言介绍&#xff1a; 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高&#xff0c;旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求&#xff0c;旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上&#xff0…...

代码随想录算法训练营第六十一天 | 108. 冗余连接 109. 冗余连接II

108. 冗余连接 题目链接&#xff1a;KamaCoder 文档讲解&#xff1a;代码随想录 状态&#xff1a;AC Java代码&#xff1a; import java.util.*;class Main {public static int[] father;public static void main(String[] args) {Scanner scan new Scanner(System.in);int n…...

RoboVQA:机器人多模态长范围推理

23 年 11 月来自 Google Deepmind 的论文“RoboVQA: Multimodal Long-Horizon Reasoning for Robotics”。 本文提出一种可扩展、自下而上且本质多样化的数据收集方案&#xff0c;该方案可用于长期和中期的高级推理&#xff0c;与传统的狭窄自上而下的逐步收集相比&#xff0c…...

TCP/IP原理详细解析

前言 TCP/IP是一种面向连接&#xff0c;可靠的传输&#xff0c;传输数据大小无限制的。通常情况下&#xff0c;系统与系统之间的http连接需要三次握手和四次挥手&#xff0c;这个执行过程会产生等待时间。这方面在日常开发时需要注意一下。 TCP/IP 是互联网的核心协议族&…...

Microsof Visual Studio Code 安装教程(中文设置)

VS Code 是一个免费的代码编辑器&#xff0c;可在 macOS、Linux 和 Windows作系统上运行。启动和运行 VS Code 既快速又简单。VS Code&#xff08;全称 Visual Studio Code&#xff09;是一款由Microsoft 推出的免费、开源、跨平台的代码编辑器&#xff0c;拥有强大的功能和灵活…...

python爬虫:Android自动化工具Auto.js的详细使用

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. Auto.js 简介2. 安装与配置2.1 安装 Auto.js2.2 安装 Python 环境2.3 安装 ADB 工具3. Python 与 Auto.js 结合3.1 通过 ADB 执行 Auto.js 脚本3.2 通过 Python 控制 Auto.js3.3 通过 Python 与 Auto.js 交互4. 常用…...

Unity DOTS从入门到精通之 自定义Authoring类

文章目录 前言安装 DOTS 包什么是Authoring1. 实体组件2. Authoring类 前言 DOTS&#xff08;面向数据的技术堆栈&#xff09;是一套由 Unity 提供支持的技术&#xff0c;用于提供高性能游戏开发解决方案&#xff0c;特别适合需要处理大量数据的游戏&#xff0c;例如大型开放世…...

linux 软件安装(上)

一、基础环境准备 1.1、安装VM 1.2、在VM上导入linux iso镜像&#xff0c;装好linux系统 华为centos镜像下载地址 https://mirrors.huaweicloud.com/centos/ https://mirrors.huaweicloud.com/centos/7.9.2009/isos/x86_64/ 网易centos镜像下载地址 htt…...

php虚拟站点提示No input file specified时的问题及权限处理方法

访问站点&#xff0c;提示如下 No input file specified. 可能是文件权限有问题&#xff0c;也可能是“.user.ini”文件路径没有配置对&#xff0c;最简单的办法就是直接将它删除掉&#xff0c;还有就是将它设置正确 #配置成自己服务器上正确的路径 open_basedir/mnt/qiy/te…...