内存管理【Linux操作系统】
文章目录
- 简单谈一下物理内存管理
- 页框
- 为什么要把物理内存划分成一个一个固定大小的页框使用?
- 对页框进行描述
- 对页框进行组织管理
- 虚拟地址→物理地址(真实的页表)
- 真实的页表
- 那我们如何把虚拟地址→物理地址呢?
- 页表懒加载时,如何确定虚拟地址对应的物理地址是否已经准备好了?
- 真实的页表中的标志位
- 页表的标志位如何保存?
- 什么时候对页表的标志位进行初始化?
- 缺页中断相关问题
- 那么操作系统是如何区分越界访问和缺页中断的呢?
简单谈一下物理内存管理
页框
操作系统管理(使用)物理内存的基本单位是页框【就是一个物理内存块,一般4kb大小
】
为什么一般是4kb大小?
因为计算机科学家研究出4kb效率最高
就像操作系统文件管理时,使用磁盘空间的基本单位也是数据块(一般也是4kb)一样
所以磁盘中的数据加载到物理内存,就非常方便了,只需要对应的数据块中的内容,加载到对应页框里面就行了
为什么要把物理内存划分成一个一个固定大小的页框使用?
而不是需要多少,就分配多少?
- ①
硬件支持与地址转换
- MMU 与页表机制:
现代 CPU 的内存管理单元(MMU)通过页表将虚拟地址转换为物理地址,而这一过程必须以固定大小的页(如 4KB、2MB、1GB)为基本单位。操作系统必须遵循硬件的这一设计,否则无法高效完成地址转换 - TLB 缓存效率:
缓冲器(TLB)缓存虚拟页到物理页框的映射。若内存分配不以页为单位,TLB 的命中率会大幅下降,导致性能急剧降低
- MMU 与页表机制:
- ②
为了提高物理内存的使用率,减少内存碎片
如果是一个一个小块地使用物理内存,那么使用物理内存时,一次最多浪费一个页框的物理内存
即最多只会出现内部碎片(即一个页框内部没有存满数据还有空隙),不会出现外部碎片(分散的小块内存难以合并)- 1.如果申请的物理内存很小,那么给它一个页框就够了
- 2.如果一次申请的物理内存很大,那么给就给它n个页框,前n-1个页框一定是全部存满数据的,第n个页框可能存不满,但就算只存了一个比特位的数据又怎样
也就浪费一个页框而已,后续使用完成之后,回收非常方便
- ③.
为了提高内存管理效率
- 元数据开销:
操作系统需要记录内存的分配状态(如空闲或占用) - 分配/释放速度:
以页为单位分配内存,操作系统只需操作页表或空闲页链表修改一下标志位,复杂度为 (O(1));而随机大小的内存块管理需要遍历更复杂的结构,效率低下
- 元数据开销:
- ④
磁盘 I/O 的协同设计
- 页缓存对齐:
Linux 将文件数据缓存在内存中,缓存的单位是页(4KB),与磁盘块(Block,通常为 4KB)对齐。
这使得:
内存和磁盘的数据交换效率更高(减少读写次数)
- 页缓存对齐:
对页框进行描述
操作系统中存在非常多的页框,每个页框的使用情况,属于谁,是否要释放等等信息操作系统都要知道
所以操作系统一定要管理页框
为了描述页框,操作系统内定义了:struct page
因为页框的个数很多,所以struct page结构体变量也很多
所以一个struct page对象的大小要尽可能的小,一般不到40字节
注意:
因为页框是物理内存块,而且页框是操作系统开机之后就一直存在的,所以描述页框的struct page也是一直存在,不会被释放的,除非操作系统关机
struct page里面我们需要关注的成员变量
-
①
unsigend long flags
:位图标志位,记录了各种各样的标志,描述页框的状态
其中就有一个:表示该页框是否被使用
所以释放(申请)物理内存(页框),就只需要改对应页框的标志位就可以了 -
②
int _mapcount
:引用计数,表示该页框被多少个进程使用
可以用于实现写时拷贝
比如:
子进程继承父进程的结构体的时候,因为结构体对象都是存储在物理内存中的,所以增加一下引用计数即可
对页框进行组织管理
操作系统中是,把struct page
结构体变量放进类似于数组
的数据结构中进行组织的
所以每一个struct page就有了下标,每一个页框就有了编号
更重要的是:
每个页框有了编号的话,那么物理地址就有了
因为
如果页框号为0的页框的起始物理地址为0,页框又是连续存放的,而且页框大小都输固定的(一般都是4kb)
所以
页框号为n的页框的起始地址=n*4*1024
(4kb=4*1024字节)
所以:
-
①我们只要有页框号就知道页框的起始物理地址
-
②只要有物理地址,
物理地址/4kb
,再取整就能得到页框号,就能找到对应的页框
所以我们只要找到struct page
结构体变量(page里面记录了自己的下标),就可以找到它对应的页框
所以进程使用物理内存,只需要记录对应的n个struct page
的地址就行了
存放所有struct page结构体变量的数组也是存储在物理内存中的
操作系统里面定义了一个全局的指针
指向这个数组的起始地址
这样在操作系统的任何地方,就都可以很方便地找到每一个struct page
,就可以知道每一个页框的使用情况
虚拟地址→物理地址(真实的页表)
真实的页表
我们之前说:
页表里面的页表项是直接左边存储虚拟地址,右边存储物理地址
但是这样其实是不行的,因为这样空间消耗太大了
如果全部的虚拟地址和物理地址都建立映射,那么就要花费至少真实的物理地址总大小的16倍的内存(因为一个字节就有一个地址,一个地址至少占4字节)
就算一个进程映射不完,但是我们现在的一些3A游戏运行时,占的内存也有7-8G,物理内存光放页表都放不下来
所以
真实的页表是:
[以32位操作系统的页表为例]
-
一个进程有一个对应的页目录,一个页目录里面一共1024个页目录项
页目录项里面存储的是某个页表的起始物理地址
-
一个页表里面也一共有1024个页表项,
页表项里面存储的是,某个页框的起始物理地址
所以一个真实的“页表”的大小最大只需要: 4*4 *1024 * 1024=16MB
因为这个就可以把整个物理内存的物理地址全部映射完
但是,一个进程可能使用全部都物理地址(内存)吗?
不可能!!!
所以其实肯定不可能页目录表里面的1024个页表全部都被使用,所以真实页表的大小一般远小于16MB
那我们如何把虚拟地址→物理地址呢?
32位平台下,一个地址占4个字节,32个比特位
所以:
-
①虚拟地址的前(从左→右)
10个比特位
,存储的就是页目录表的下标
,用于在页目录里面指定,要用那个页目录表项,就找到了页表[因为1024=2^10] -
②虚拟地址的
中间10个比特位
,存储的就是页表的下标
,用于在页表中指定,要用那个页表项,就找到了页框 -
③虚拟地址
最后12个比特位
,就是表示相对于对应的页框的起始物理地址的偏移量[因为2^12=4096=4kb]
这样虚拟地址就可以转换成物理地址了
所以上面的映射说明,虚拟地址和物理地址其实有一定的关系?
其实没有,虚拟地址和物理地址建立映射之前,没有任何联系
,它们之间是完全解藕的
只有映射了之后,才通过上面说的结构有了联系
那为什么上面的结构能够映射呢?
-
那是因为编译器编译形成可执行文件的时候,就已经进行了虚拟地址的编址,所以可执行程序的代码和数据,加载到物理内存时也是以4kb为单位的
-
所以加载时,
就随意加载到哪个页框
,只要得知这个页框的起始物理地址即可,因为代码/数据加载到了页框,所以页框的起始物理地址就有了对应的虚拟地址了 -
再根据页框的起始物理地址对应的虚拟地址的中间10位,先创建(查找)一张页表,再把页框起始物理地址,填充到页表对应的页表项里
-
再根据可执行文件编好的虚拟地址填充,把页表的物理地址填充到对应的(
即页目录里面不一定是从0→1023连续填充的,可能隔开
)页目录的下标中 -
所以建立虚拟地址和物理地址一开始加载代码和数据时,建立映射的时候是填充页表→填充页目录表,当然如果懒加载了也没问题
就算只加载进程的入口函数(一般是_start函数)的地址,也没事
因为如果MMU硬件顺着虚拟地址找到的物理地址还没填充数据,那直接填充不就行了
所以
一般情况下,虚拟地址和物理地址的映射,在程序加载到内存时,就已经建立好了
如下图
页表懒加载时,如何确定虚拟地址对应的物理地址是否已经准备好了?
页表懒加载
即进程加载代码和数据的时候,不一定运行了就会把所有的代码和数据加载进来
只要能够在需要的时候,能及时加载进来就可以了
即:
如何知道虚拟地址对应的物理地址中,有没有需要的数据呢?
如果懒加载(以进程最开始的为例,运行过程中懒加载也是类似):
-
那就是拿着进程PCB中存储的入口函数(_start函数)的虚拟地址,创建页目录表,再创建一张页表
-
再根据前10比特位,把页表起始物理地址填充到页目录表的指定下标位置
-
再根据中间10比特位,查询页表
但是不填充具体页框的物理地址,而是直接填nullptr(至少前20比特位为全0,因为可能顺便设置页表标志位
) -
这样运行进程时,MMU查找到页表时,发现是页框地址是nullptr,那就是这个页框的代码和数据还没有准备好,
自然就触发缺页中断了
综上:
- 硬件上:物理内存是没有权限控制的(即谁都可以读写)只要知道物理地址就能读写
- 软件上:物理内存才有权限控制,所以物理内存的权限控制是软件做的
真实的页表中的标志位
页表的标志位如何保存?
32位下真实的页表是:
页目录表里面存了1024张页表的起始地址,一个页表里面存了1024个页框的起始物理地址
但是我们之前不是还说过,页表里面有标志位,来进行权限管理之类的操作吗?
如果我们细心观察就会发现:
所有的页框的起始物理地址的最低的12个比特位都是0
因为2^12=4096=4kb
而且每个页框的大小都是4kb,所以其实每个页框的起始物理地址都是4kb的整数倍
所以最低的12个比特位是用来存储:从0到4095的
例如:
第一个页框的起始物理地址为全0
第二个页框的起始物理地址为
00000000000000000001000000000000
第3个页框:
00000000000000000010000000000000
…
而
页表里面的页表项只存储页框的起始物理地址
那我们可不可以利用这空的12个比特位,来存储页表的相关标志位呢?
如下图,就是Linux操作系统中页表实现的一部分
因为页表项和页目录项的数据类型是
unsigned long
所以页表和页目录表本质就是元素为unsigned long类型的数组
什么时候对页表的标志位进行初始化?
可执行文件加载到内存的时候!!!
因为编译器编译形成可执行文件的时候,就已经分好了数据节了
而数据节就已经有权限位了
只要加载进来就可以直接初始化!!!
查页表的标志位和权限位,看是否有权限,也是MMU硬件在虚拟地址→物理地址时做的
所以如果因为权限位/标志位(修改代码区,懒加载导致的需要的代码数据还没加载到内存等问题)
导致地址转换失败,本质就是CPU运算出错(因为MMU就是CPU的一部分)
CPU就会在状态寄存器中打上对应的标志位,在合适的时候触发软中断切换到操作系统给进程发送中断信号
缺页中断相关问题
产生缺页中断的情况就是:尝试访问的页框中的数据不在物理内存中
(注意:野指针/权限错误不叫缺页中断,它们是错误
)
-
①
因为懒加载的原因
,虚拟地址找到的页表中还没有存放对应页框的起始物理地址(存的是nullptr) -
②
因为内存不足时
,挂起导致的进程一部分代码和数据换出(本质就是对应页框中的数据换出),此时虚拟地址找到的页表指向的是换出的页框,页表项中有页框的起始物理地址,但是没有代码和数据
所以有了缺页中断
new和malloc的时候,其实就只需
- ①申请并填充vm_aere_struct节点
- ②填充页目录项和对应的页表项
- ③存放在页表中的页框的起始物理地址为全0
- ④是否命中的标志位置为0
进程申请物理内存要做的操作都是与上面类似的
为什么这么做?
-
1.这样就在申请了但还没使用的区间中,暂时性的节省物理内存
要使用时缺页中断就可以了 -
2.进程只管自己的进程地址空间和页表,物理内存的操作都归操作系统管理
这样就把进程管理和内存管理解藕了
同理未初始化的虚拟内存块(变量,数组等)也和还没被使用的new出来的空间一样,还没有真正与之对应的物理内存块
那么操作系统是如何区分越界访问和缺页中断的呢?
因为虚拟地址触发越界访问和缺页中断时,都是虚拟地址与对应的物理地址还没有真正建立映射
其实很简单:就是代码和数据的范围
因为进程地址空间中,真正有虚拟和物理地址映射的虚拟内存区域都在vm_area_struct
链表里面存着
操作系统通过vm_area_struct至少也大概知道(因为不可能真去遍历链表)进程的代码和数据的范围
所以不在这个链表节点范围的肯定就是越界访问了
具体细节:
在Linux中,当进程访问虚拟地址时,若未找到对应的数据或代码,操作系统通过以下机制区分是野指针(无效地址)还是缺页错误(有效地址但数据未加载):
-
虚拟地址空间的合法性检查
每个进程的虚拟地址空间由内核维护,包含多个映射区域(如代码段、堆、栈、共享库等)。这些区域通过vm_area_struct结构体描述,记录每个区域的起始地址、结束地址、权限(读/写/执行)等。
当发生页错误(Page Fault)时,内核首先检查触发错误的虚拟地址是否属于某个已存在的vm_area_struct区域:
合法地址:若地址在某个区域范围内,说明是有效地址,可能是缺页错误或权限错误。
非法地址:若地址不在任何区域范围内,直接判定为野指针访问,触发SIGSEGV信号(段错误),进程通常终止。 -
页表项(Page Table Entry, PTE)状态分析
若地址合法,内核进一步检查页表项(PTE)的状态:
页面未加载(缺页错误):
PTE的**存在位(Present Bit)**为0,但地址对应的区域有效(如文件映射、匿名内存或交换空间)。
内核会尝试从磁盘(如交换分区或文件)加载页面到物理内存,并更新页表。
权限错误:
PTE存在(Present Bit=1),但操作违反权限(如写只读页)。
触发SIGSEGV信号(例如尝试修改代码段的只读页)。 -
错误类型的最终判定
野指针:地址不在任何vm_area_struct区域 → SIGSEGV。
缺页错误:地址合法且属于某个区域,但页面未加载 → 触发页面调度(Page-in)。
权限错误:地址合法但操作违反权限 → SIGSEGV。 -
内核处理流程(简化版)
Page Fault发生
↓
CPU将错误地址和原因(读/写/执行)传递给内核
↓
内核检查地址是否在进程的vm_area_struct链表中
├─ 不在 → 触发SIGSEGV(野指针)
└─ 存在 → 检查PTE状态
├─ 页面未加载(Present Bit=0)→ 调入页面(缺页处理)
└─ 权限错误 → 触发SIGSEGV
总结
- 野指针:访问未映射的虚拟地址 → 内核直接终止进程。
- 缺页错误:访问已映射但未加载的地址 → 内核透明加载数据,进程无感知。
- 权限错误:访问合法地址但违反权限 → 内核终止进程。
操作系统通过虚拟地址空间管理和页表状态分析,精准区分不同类型的错误,确保进程行为受控且内存访问高效安全。
相关文章:

内存管理【Linux操作系统】
文章目录 简单谈一下物理内存管理页框为什么要把物理内存划分成一个一个固定大小的页框使用?对页框进行描述对页框进行组织管理虚拟地址→物理地址(真实的页表)真实的页表那我们如何把虚拟地址→物理地址呢?页表懒加载时ÿ…...

Go语言学习-->从零开始搭建环境
Go语言学习–>从零开始搭建环境 1 开发环境 Go官网下载地址:https://golang.org/dl/ Go官方镜像站(推荐):https://golang.google.cn/dl/ windos 平台下载: 我这里下载1.22稳定版 双击下载好的.msi文件 修改安装…...

【力扣】3403. 从盒子中找出字典序最大的字符串 I
解法一: class Solution {public String answerString(String word, int numFriends) {//对字符的划分,word长度为n,共有n1个位置可以插入,但是要求被分为非空字符串,所以插入的位置最多为n-1。int n word.length();…...
苹果企业签名撤销
苹果企业签名证书被撤销的原因通常涉及违反苹果的**《Apple Developer Program企业协议》**或相关安全政策,以下是常见原因: ### 一、核心违规原因 1. **证书滥用分发公开应用** * 企业证书仅限**内部员工使用**,若用于以下场景会被撤销&…...
12306高并发计算架构揭秘:Apache Geode 客户端接入与实践
目录 Apache Geode 客户端入门指南 一、安装 Apache Geode 二、启动 Geode 集群 三、Java 客户端接入 Geode Maven 示例依赖 Gradle 示例依赖 Java 示例代码 四、Spring Boot 客户端接入 Geode Maven 配置 Gradle 配置 运行应用 五、Apache Geode 原生客户端 .NET…...
JSON to Excel 3.0.0 版本发布 - 从Excel插件到Web应用的转变
1. 简介 JSON to Excel 3.0.0 是一个重大更新版本,将原有的Excel插件扩展为完整的Web应用。现在您可以直接在浏览器中使用它,无需安装任何插件。所有的转换在浏览器中完成,预览后,可点击下载按钮,导出成xlsx格式文件。…...

【前端】Vue3+elementui+ts,给标签设置样式属性style时,提示type check failed for prop,再次请出DeepSeek来解答
🌹欢迎来到《小5讲堂》🌹 🌹这是《前端》系列文章,每篇文章将以博主理解的角度展开讲解。🌹 🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!&…...
Neo4j 监控全解析:原理、技术、技巧与最佳实践
高效的监控是保障 Neo4j 图数据库性能、稳定性和可观察性的基石。本文将深入探讨 Neo4j 监控的核心原理、关键技术、实用技巧及行业最佳实践,助您构建强大的数据库运维体系。 掌握这些监控技术,将使您的 Neo4j 数据库在稳定性、性能和可维护性上达到企业…...

PyTorch——优化器(9)
优化器根据梯度调整参数,以达到降低误差 import torch.optim import torchvision from torch import nn from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear from torch.utils.data import DataLoader# 加载CIFAR10测试数据集,设置tr…...

07 APP 自动化- appium+pytest+allure框架封装
文章目录 一、PO二、代码简单实现项目框架预览:base_page.pydir_config.pyget_data.pylogger.pystart_session.pyconfig.yamlkey_code.yamllaunch_page_loc.pylogin_page_loc.pylaunch_page.pylogin_page.pytest_login.pypytest.inirun.py 一、PO PO 分为四层 &…...
Postgresql常规SQL语句操作
目录 一、数据库与对象管理 二、数据操作 (CRUD) 三、查询优化与执行计划分析 四、事务控制 五、数据类型与高级特性应用 六、系统查询与维护 研发中的重要注意事项 在 PostgreSQL 研发中,以下这些 SQL 应用是极其常见且核心的操作,涵盖了数据库设…...
智能合约安全漏洞解析:从 Reentrancy 到 Integer Overflow
目录 🌀 Reentrancy(重入攻击) 原理解析 典型案例:The DAO 攻击事件 漏洞示例 防范措施 🔢 Integer Overflow(整数溢出) 原理解析 漏洞示例 防范措施 🛡️ 总结与建议 随着…...

英国2025年战略防御评估报告:网络与电磁域成现代战争核心
英国 2025 年战略防御评估 (SDR) 详细制定了一项计划,通过加强使用网络、人工智能和数字战争来整合其军事防御和进攻能力。 与美国一样,英国也被认为(尽管未被公开证实)会开展进攻性网络行动,甚至针对盟友。斯诺登泄露…...

基于QPSK调制解调+Polar编译码(SCL译码)的matlab性能仿真,并对比BPSK
目录 1.引言 2.算法仿真效果演示 3.数据集格式或算法参数简介 4.MATLAB核心程序 5.算法涉及理论知识概要 6.参考文献 7.完整算法代码文件获得 1.引言 Polar码由土耳其教授Erdal Arikan于2008年提出,是第一种被严格证明可以达到香农极限的构造性编码方法。其核…...
go语言学习 第5章:函数
第5章:函数 函数是编程中不可或缺的一部分,它封装了一段可重复使用的代码,用于执行特定的任务。在Go语言中,函数同样扮演着重要的角色。本章将详细介绍Go语言中函数的定义、调用、参数传递、返回值处理以及一些高级特性ÿ…...
Qt Quick快速入门笔记
Qt Quick快速入门笔记 基本的程序结构int main(int argc, char *argv[]) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endifQGuiApplication app(argc, argv);QQmlApplicationEngine engine;const QUrl ur…...
《波段操盘实战技法》速读笔记
文章目录 书籍信息概览实战八法波段见顶信号中长线大顶形态投资理念 书籍信息 书名:《波段操盘实战技法》 作者:何瑞东 概览 实战八法 投资理念和投资理论概述:波段操作的核心是通过捕捉股价波动中的趋势性机会,结合技术分析与…...

Glide NoResultEncoderAvailableException异常解决
首先将解决方法提出来:缓存策略DiskCacheStrategy.DATA。 使用Glide加载图片,版本是4.15.0,有天发现无法显示gif图片,原始代码如下: Glide.with(context).load(本地资源路径).diskCacheStrategy(DiskCacheStrategy.A…...
工厂模式与多态结合
工厂模式与多态的结合是平台化项目中实现灵活架构的核心技术之一。这种组合能够创建可扩展、易维护的系统架构。 多态(Polymorphism)指同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。 例子1: public abstract class Pay…...

无人机巡检智能边缘计算终端技术方案——基于EFISH-SCB-RK3588工控机/SAIL-RK3588核心板的国产化替代方案
一、方案核心价值 实时AI处理:6TOPS NPU实现无人机影像的实时缺陷检测(延迟<50ms)全国产化:芯片、操作系统、算法工具链100%自主可控极端环境适配:-40℃~85℃稳定运行,IP65防护等…...
相机--相机成像原理和基础概念
教程 成像原理 基础概念 焦距(物理焦距) 镜头的光学中心到感光元件之间的距离,用f表示,单位:mm;。 像素焦距 相机内参矩阵中的 fx 和 fy 是将物理焦距转换到像素坐标系的产物,可能不同。…...

2025-0604学习记录17——文献阅读与分享(2)
最近不是失踪了!也不是弃坑了...这不是马上要毕业了嘛!所以最近在忙毕业论文答辩、毕业去向填报、户档去向填报等等,事情太多了,没顾得上博客。现在这些事基本上都解决完了,也有时间静下心来写写文字了~ 想要写的内容…...

图解浏览器多进程渲染:从DNS到GPU合成的完整旅程
目录 浅谈浏览器进程 浏览器进程架构的演化 进程和线程关系图示 进程(Process) 线程(Thread) 协程(Coroutine) 进程&线程&协程核心对比 单进程和多进程浏览器 单进程浏览器编辑 单进程…...

【计算机网络】第3章:传输层—TCP 拥塞控制
目录 一、PPT 二、总结 TCP 拥塞控制详解 ⭐ 核心机制与算法 1. 慢启动(Slow Start) 2. 拥塞避免(Congestion Avoidance) 3. 快速重传(Fast Retransmit) 4. 快速恢复(Fast Recovery&…...

idea不识别lombok---实体类报没有getter方法
介绍 本篇文章,主要讲idea引入lombok后,在实体类中加注解Data,在项目启动的时候,编译不通过,报错xxx.java没有getXxxx()方法。 原因有以下几种 1. idea没有开启lombok插件 2. 使用idea-2023…...
【Hive入门】
之前实习写的笔记,上传留个备份。 1. 使用docker-compose快速搭建Hive集群 使用docker快速配置Hive环境 拉取镜像 2. Hive数据类型 隐式转换:窄的可以向宽的转换显式转换:cast 3. Hive读写文件 SerDe:序列化(对象转为字节码…...
亚马逊站内信规则2025年重大更新:避坑指南与合规策略
亚马逊近期对Buyer-Seller Messaging(买家-卖家站内信)规则进行了显著收紧,明确将一些曾经的“灰色操作”列为违规。违规操作轻则收到警告,重则导致账户暂停或绩效受限。本文为您全面解析本次规则更新的核心要点、背后逻辑&#x…...
01 - AI 时代的操作系统课 [2025 南京大学操作系统原理]
01 - AI 时代的操作系统课 [2025 南京大学操作系统原理] [00:00:00]-[D:\movie\南京大学操作系统\01-AI时代的操作系统课[2025南京大学操作系统原理].mp4] 大家好!我是姜艳艳,来自南京大学计算机软件研究所。今天我们开启《操作系统原理》的第一课&…...
数组1 day7
六:数组 一:数据类型 1.int a[10] //想要知道一个标识符对应的数据类型,去掉标识符,剩下就是它对应的数据类型 //eg:a所谓代表的类型,就是int[10]这种类型(是一个数组,包含10个…...

SAP学习笔记 - 开发15 - 前端Fiori开发 Boostrap,Controls,MVC(Model,View,Controller),Modules
上一章讲了Fiori开发的准备,以及宇宙至简之HelloWorld。 SAP学习笔记 - 开发14 - 前端Fiori开发 HelloWorld-CSDN博客 本章继续学习 Fiori 开发的知识: Bootstrap,Controls,MVC(Model,View,Controller&a…...