计算机组成原理笔记(三)
四、存储系统
1.存储器概述
- 存储器分类
划分依据 | 具体分类 |
---|---|
存取方式 | 随机存储器(半导体存储器)、顺序存储器(磁带)、直接存储器(磁盘) |
读写功能 | 只读存储器($ROM$)、读写存储器($RAM$) |
作用 | 控制存储器、高速缓冲存储器$Cache$、主存储器、辅助存储器(磁盘) |
存储系统技术指标
存储时间:从接受到读写命令到从存储器中读出或写入信息所经历的时间
存储周期:连续两次访问存储器所需要的最小时间间隔 (存储时间+恢复时间)
存储器带宽:单位时间内存储器存取的信息量,单位为$Byte/s$
基本存储体系
- 基本存储体系运作流程
- 输入设备将程序与数据写入主存;
- $CPU$取指令;
- $CPU$执行指令期间读数据;
- $CPU$写回运算结果;
- 输出设备输出结果。
- 基本存储体系的问题
- 主存速度慢:主存增速与$CPU$增速不同步,指令执行期间多次访问主存
- 主存容量不足:存在制约主存容量的技术因素(由$CPU$、主板等相关技术指标确定),应用对主存的需求不断扩大,存在价格约束
- 基本存储体系运作流程
存储体系的层次化结构
使用高速缓冲存储器($Cache$):解决$CPU$与主存速度不匹配的矛盾
$L1\enspace Cache$集成在$CPU$中,分数据$Cache(D-Cache)$和指令$Cache(I-Cache)$
早期$L2\enspace Cache$在主板上或与$CPU$集成在同一电路板上。随着工艺的提高,$L2\enspace Cache$被集成在$CPU$内核中,不分$D-Cache$和$I-Cache$
使用辅存(磁盘、磁带、网络存储):解决主存容量和价格限制
$CPU$访问到的存储系统具有$Cache$的速度,辅存的容量和价格
存储单元、存储地址与边界对齐
主存由半导体$MOS$存储器组成,给出一个地址,经过一个存储周期,可以访问一个存储单元;
存储单元比特位数和机器字长有关,$32$位计算机中主存单元是$32$位,$64$位计算机主存单元是$64$位;
以$32$位计算机为例,$32$位字长的主存单元可以按照不同大小访问,既可以按照字节访问,也可以按照半字$16$位或者字存储单元$32$位进行访问;
不同访问模式的访问时间都是一个存储周期,访问地址分别对应字节地址、半字地址和字地址;
例如对于以下指令:
$mov\enspace ah, [8]$ #按字节访存 $ah=0x12$
$mov\enspace ax, [8]$ #按半字访存 $ax=0x3412$
$mov\enspace eax,[8]$ #按字访存 $eax=0x78563412$
$mov\enspace eax,[9]$ #未对齐,产生异常强制边界对齐
- 计算机中只有字节地址;
- 按半字访问时屏蔽字节地址最低位,也即半字地址必须按$2$对齐;
- 按字访问是屏蔽字节地址最低$2$位,也即字地址必须按$4$对齐;
- 如果不对齐,将导致访问数据不在一个存储单元中,需要两个以上的存储周期才能得到,计算机中不允许出现这种情况,因为这样的指令执行会产生数据未对齐异常。
2.主存的组织及与$CPU$的连接
字长扩展(数据总线扩展)
各芯片并行工作,数据由多个芯片的输出组合得到
设存储系统位宽$N$位,若使用$k$位芯片,$k<N$,需$(N/k)$个芯片
字数扩展(地址总线扩展)
同一时刻仅一个芯片工作,数据由一个芯片的输出得到
设存储系统容量为$M$,若使用容量为$l$的芯片,$l<M$,需$(M/l)$个芯片
综合扩展
存储系统$M\times N$位,若使用$l\times k$位的芯片,$l<M,k<N$,需$(M/l)\times (N/k)$个芯片
3.并行主存系统
双端口存储器
- 具有两组相互独立的读写控制线路
- 两组读写控制线路可以并行操作
- 端口地址不相同,无冲突,并行存取
- 端口地址相同,读写冲突,无法并行存取
多体交叉存储器
高位多体交叉
- 一个地址寄存器
- 高位片选,多模块串行
- 扩容方便
低位多体交叉
- 每个存储体均需地址寄存器
- 低位片选,模块并行工作
- $CPU$比存储器要快,能同时取出多条指令或者数据
- 扩容方便
低位多体交叉下的流水线访问
设模块存取周期为$T$,总线传输周期为$t$,存储器交叉模块数为$m$;
流水线方式存取的条件:$T=m\times t$;
即每个模块启动后经过$t$时间的延时,就可以启动下一个模块;
连续并行读$m$个字的时间:$t_1=T+(m-1)t$
顺序读$m$个字的时间:$t_2=mT$
4.高速缓冲存储器
(1)缓冲工作原理
早期$U$盘
早期计算机中,如果要拔出$USB$设备,计算机会提示进行安全拔出
早期$U$盘写速度慢,计算机会将部分内存空间为$U$盘作写缓冲;
当数据写入内存时,计算机即报告传输完成,这样可以改善用户等待体验;
但同时会导致数据不一致性,产生脏数据——在内存中还未写入$U$盘的数据;
系统将定时或被迫将脏数据迁移到U盘,不安全的拔盘可能丢失脏数据。
缓冲机制
- 缓冲的前提
- 有较大性能差异(如$CPU$和主存)
- 缓冲空间足够
- 快存为慢存作写缓冲,优化写性能
- 缓冲的前提
(2)程序局部性原理
程序局部性:程序仅需访问内存很小一部分空间
空间局部性: 某内存区域刚被访问,很快其相邻区域有可能被访问
数据——连续数组元素访问
数据——结构体、数据库记录访问
指令——顺序访问的指令
时间局部性: 某内存区域刚被访问,很快该区域可能会被重复访问
- 数据——局部变量,计数器,指针等被重复使用
- 指令——重复使用的循环体中的指令
- 指令——子函数的调用
读性能的优化
- 利用数据访问的空间局部性进行读优化
- 将热数据或即将访问数据的副本调度到存储系统上层
- 仅访问上层快存即可获得数据
$cache$的基本思想
在处理器附近增加一个隐藏的小容量快速存储器
- 采用硬件实现,程序员无法操纵
- 高命中率优化读性能
- 预读处理——空间局部性(预读相邻的数据)
- 淘汰算法——时间局部性(淘汰掉最近最不常访问的数据)
- 将热数据副本存放在$cache$中
读操作流程
命中($HIT$)
$CPU$发出读请求,要访问的数据可以在$cache$中找到,直接返回数据
缺失($MISS$)
$CPU$发出读请求,要访问的数据在$cache$中无法找到,需要在主存中找到后拷贝到$cache$中,再返回数据,这将导致访问速度急剧下降
写操作流程
写穿策略($WriteThrough$)
CPU发出写请求,将要写入的数据写入cache和主存中,写入完成后响应,无脏数据,无丢失数据的风险,写速度慢
写回策略($WriteBack$)
CPU发出写请求,将要写入的数据写入$cache$中即返回写响应,存在脏数据,有丢失数据的风险,突发写速度快;持续写时,$cache$很快就会存满数据,需要先将$cache$中数据移到主存,然后再写入$cache$
(3)cache基本概念
命中$(hit)$:$CPU$访问数据在$cache$中(上层存储器)
缺失$(miss)$:$CPU$访问数据不在$cache$中
块$(block)$:$cache$与主存交换最小单位
- 块越小,时间局部性越好,过小会导致频繁交换;
- 块越大,空间局部性越好,过大导致$cache$很快会被装满,对热数据的调度差
行/槽$(Line/Slot)$:包括有效位、查找标记、脏标志位、置换标志、数据块副本的容器
命中率$(hit\enspace rate)$:主存访问中$cache$命中比例
缺失率$(miss\enspace rate)$:1-命中率
命中访问时间$(hit\enspace time)$:包括数据查找时间、$cache$访问时间、总线传输时间
缺失损失$(miss\enspace penalty)$:主存块调入$cache$,数据传输到$CPU$的时间,远大于命中时间
(4)cache读流程
- $CPU$给出主存地址
- 以主存块地址为关键字在$cache$中查找,需要维护查找表
- 如相符表示副本在$cache$中,命中,访问$cache$
- 否则数据缺失,访问主存
- 将数据所在块的副本调入$cache$
- 更新查找表,记录当前数据块地址
- 载入副本过程可能引起替换
- $cache$缺失时,CPU需要等待数据调入
(5)cache写流程
- $CPU$给出主存地址
- 以主存块地址为关键字进行查找
- 相符:表示命中,数据副本在$cache$中
- 缺失:根据写分配策略决定是否将该主存地址对应数据块调入
- 写分配:为主存块分配$cache$行
- 写不分配:静默地将数据写入主存,而不分配$cache$行
- 写入数据到$cache$,并根据写策略决定是否写入主存
(6)cache查找机制
- 解决判断数据是否在$cache$中的问题,查找时间应快速且一致,不随着数据增长而增长
- 相联存储器:按内容进行访问的存储器
主存块号 | $cache$块号 |
---|---|
001 | 1 |
021 | 2 |
023 | 6 |
$\dots$ | $\dots$ |
读逻辑实现
- 查找表中有内容的$key-value$对的$valid$位置为$1$,否则$valid$位为$0$;
采用多个比较器进行并发比较,每次比较时$L_0-L_7$至多有一个为$1$;
- 根据$valid$位和比较结果使用三态门输出$key$对应的$value.$
相联存储器的特点
按内容进行访问$(Key,Value)$
- 以关键字进行全局并发比较
- 硬件成本较高(比较器多),通常用于存放查找表或全相联$cache$
存储容量=查找表容量=表项数$\times $表项大小
- $cache$中用于存放块表,虚拟存储器中用于存放段表、页表
模式 | 有效位 | $Key$ | $Value$ |
---|---|---|---|
$cache$ | 有效位 | 主存块地址 | $cache$块地址 |
虚拟存储器 | 有效位 | $VPN$ | $PPN$ |
$CPU\enspace cache$的基本组织方式
- $CPU\enspace cache$由较快的$SRAM$构成
- $cache$与主存均分为固定大小的数据块,以块为单位交换数据
- 相联存储器存放查找表/$cache$
- 表项:(有效位,调入$cache$的主存块地址,$cache$块地址/$block\enspace data$)
- 容量 = $cache$块数 * 表项大小
- 块地址与块内地址
- 由于主存被分为若干主存块,每个主存块包含多个存储单元,因此主存地址可以分为块地址和块内偏移;
- 查找表表项内容为(valid,主存块地址,cache块地址)
- 查找表表项数目$=cache$块数目,总容量$=(1+11+8)*2^8$
(7)cache映射机制
- 解决如何将主存数据放置在$cache$行中的问题,有规律的映射有助于查找
- 利用某种方法或规则将主存块定位到$cache$称为地址映射
- 全相联$(fully-associated)$
- 直接相联$(direct\enspace mapped)$
- 组相联$(set-associated)$
①全相联
主存块可以放置在任意$cache$行;
主存地址为:(主存块地址,块内偏移)
$cache$行内容为:(有效位,主存块地址,数据块副本)
实现时可以直接将数据块副本存放在$cache$行中,而不需要$cache$块地址;
关系图
逻辑实现
相联存储器容量
- 查找表和缓存副本一体(CPU片内缓存)
- 存放$cache$行
- 有效位、主存块地址、数据块副本、标志位$(Dirty\enspace bit)$、置换标记
- 存储容量$=cache$行大小$\times$行数
- 查找表和缓存副本分离(片内查找表,片外缓存)
- 查找表在$CPU$内部,存放查找信息,而缓存在主存上
- 先将主存块地址翻译为$cache$块地址,再通过$cache$块地址访问片外缓存
- 有效位、主存块地址、$cache$块地址、标志位$(Dirty\enspace bit)$、置换标记
- 存储容量$=$查找表表项大小$\times$行数
- 查找表和缓存副本一体(CPU片内缓存)
应用场合
- 块映射灵活,一对多映射
- 块冲突概率低,$cache$装满后才会出现块冲突,$cache$利用率高
- 命中率高
- 淘汰算法复杂
②直接相联
将主存块分为若干个区,每个区内的主存块只能放在区内索引相同的$cache$行内;
主存地址为:(区地址,行索引,块内偏移)
$cache$行内容为:(有效位,主存块地址,数据块副本)
关系图
逻辑实现
$cache$容量
- 使用一个比较器,比较标记——区地址
- cache容量=行大小$\times$行数=(valid+脏数据标志+比较标记+数据块)$\times$行数
应用场合
- 映射速度快(但是存在译码逻辑),一对一映射,无须查表
- 利用索引字段直接对比相应标记位即可
- 查找表可以和副本一起存放,无需相联存储器
- 容易冲突,$cache$利用率低
- 命中率低,适合大容量$cache$
- 无需替换算法,按行索引替换
- 映射速度快(但是存在译码逻辑),一对一映射,无须查表
③组相联
组内全相联,组间直接相联;
将$cache$分为若干个组,每组有若干个$cache$行,在进行映射时,第$i$个主存块只能放在第$i$组,组内可以任意放置;
主存地址为:(标记tag,组索引,块内偏移)
$cache$行内容为:(有效位,标记tag,数据块副本)
关系图
逻辑实现
存储容量
- 多个相联存储器共享一个多路比较器(一组内的行数)
- 多路比较器复杂度比简单的全相联模式低
- 查找表表项内容:(valid,dirty,查找标记,置换标记位)
- 相联存储器总容量:cache行数$\times$(1+1+查找标记宽度+置换标记位)
- 多个相联存储器共享一个多路比较器(一组内的行数)
④不同映射机制对比
不同映射机制的主存地址划分
不同映射机制的应用场合
- 小容量$cache$可采用全相联映射或组相联映射
- $Pentium\enspace CPU:L_1\enspace L_2\enspace cache$
- 大容量$cache$可采用直接映射方式
- 查找速度快,命中率相对低,但$cache$容量大可提高命中率块,设备缓存
- 小容量$cache$可采用全相联映射或组相联映射
(8)cache替换策略
- 解决cache满或者冲突时如何进行替换的问题,需要考虑时间局部性
- 先进先出法——$FIFO$
- 最近最不经常使用方法——$LFU$
- 近期最少使用法——$LRU$
- 随机替换法
(9)cache写入策略
- 解决如何保证cache与memory的一致性的问题
- 写回法($cache$中需要维护脏数据标志位)
- 写穿法($cache$中不需要维护脏数据标志位)
- 写分配
- 写不分配
(10)总结
①cache对存储系统性能的影响
- 读优化
- 时间局部性:将刚访问的数据调度到$cache$中、利用淘汰算法将不经常使用的数据淘汰
- 空间局部性:大块预读,相邻的数据被调度到$cache$中
- 写优化
- 写回策略提升突发写性能
- 负面影响
- 写回策略引起数据的不一致性
- $cache$装满后,写性能降低
②cache命中率的影响因素
命中率:设$N_c$表示$cache$完成存取访问的总次数,$N_m$表示主存完成存取访问的总次数,则命中率$h=\frac{N_c}{N_c+N_m}$
平均访问时间$t_a$:设$t_c$表示命中$cache$时的访问时间,$t_m$表示命中主存时的访问时间,则平均访问时间$t_a=ht_c+(1-h)t_m$
访问效率:$t_c/t_a$
$cache$容量越大,命中率越高
块的大小与命中率
块大小越大,块数量越少,空间局部性越好,时间局部性不佳,缺失率提升,具体关系如下图
极端情况下,当一个$cache$仅有一块时,命中率急剧下降
地址映射与命中率:全相联$>$组相联$>$直接相联
5.虚拟存储器
(1)工作原理
如左图所示,在实地址计算机系统中,程序直接访问和操作的都是物理内存
- 用户程序可以访问任意内存,寻址内存的每个字节,很容易破坏操作系统,造成操作系统崩溃;
- 同时运行多个程序特别困难,多个程序可能会对同一个物理地址对应的存储单元进行操作,使得程序崩溃。
而如右图所示,现代处理器使用虚拟寻址(Virtual Addressing)方式
- 使用虚拟寻址方式,$CPU$需要将虚拟地址翻译成物理地址,才能访问到真实的物理内存;
- 当在查找表中找到虚拟地址对应的表项时,即可得到物理地址;
- 当未找到虚拟地址对应的表项时,需要从外存中调入相应数据到内存中。
基于局部性原理的虚拟存储器
- 基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其他部分留在外存,就可以启动程序执行;
- 由于外存往往比内存大很多,所以待运行程序所需的内存大小可以比物理内存容量大;
- 在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序;
- 另一方面,操作系统将内存中暂时不使用的内容换到外存上,从而腾出空间存放将要调入内存的信息。
- 这样,计算机好像为用户提供了一个比物理内存大得多的存储器,这也就是虚拟存储器。
虚拟内存的好处
- 通过虚拟内存可以让程序拥有超过系统物理内存大小的可用内存空间;
- 虚拟内存为每个进程提供了一个一致的、私有的地址空间,使得在进程端看来,其拥有一片连续完整的内存空间,以更加有效地管理内存并减少出错;
- 实际上,应用程序使用的内存空间通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
虚拟存储器的特点
- 虚存处于主存-辅存存储层次;
- 作用:解决主存容量不足的问题,为程序员提供比主存空间大的编程空间;
- 分类:页式虚拟存储器、段式虚拟存储器、段页式虚拟存储器;
- 需要解决的问题
$CPU$访问存储系统的地址属性
- 使用虚存后,辅存的访问方式是逻辑地址空间,而主存的访问方式是物理地址空间
- 采用$MMU(Memory\enspace Management\enspace Unit)$管理虚拟地址和物理地址
判断$CPU$访问的信息是否在主存中
- 当不在主存上时,需要将逻辑地址空间中的数据调入到主存中
- 采用页表判断$CPU$将访问的信息是否在主存,并与$MMU$配合实现逻辑地址与物理地址之间的转换
- 页表存放在主存中
虚拟存储器的地址划分
- 虚拟地址由虚页号和页偏移量组成;
- 虚页号与页表项数有关,页偏移量与物理页大小有关;
- 如果主存页大小为$4K$,虚存大小为$4GB$,则页内偏移量为$12$位,虚拟页号为$32-12=20$位,对应的页表有$1024*1024$项。
(2)地址映射与变换
①虚拟存储系统的层次结构
CPU不能用虚拟地址访问cache,因为虚拟地址不具有唯一性。
②虚拟存储器的实现
- 程序执行时,按需载入代码和数据(节省空间)
- 虚存机制由硬件与操作系统协作实现
- 硬件$(MMU)$将虚拟地址转化为物理地址
- 缺页时,由操作系统进行主存和磁盘之间的信息交换
③虚拟存储器与$cache$的相似之处
- 将程序中常用的部分驻留在高速存储器
- 程序载入都是按需载入(不是全部载入)
- $cache$分块,虚拟存储器分页
- $cache$空间满,需要将不常用的数据淘汰到主存中
- 主存空间满,需要将不常用程序或数据淘汰或交换到辅存中
- 数据调度由硬件(对于$cache$)或操作系统(对于悉尼存储器)完成,对用户透明
④虚拟存储器与$cache$的不同之处
设计初衷
- $cache$使存储系统的性能接近于高速存储器
- 虚拟存储器扩充主存容量,降低价格成本
虚存中未命中性能损失远大于$cache$系统
- 这是因为缺页处理需要访问磁盘,而$cache$缺失只需要访问主存,带来的开销远小于缺页。
- 使用全相联提升命中率
- 使用更大的交换单位页
- 使用近似$LRU$算法 ($CLOCK$算法)
虚存由硬件和$OS$联合管理,$cache$由硬件管理
(3)页式虚拟存储器
①页式虚拟存储器的结构
- 虚拟地址不具有唯一性,对于不同的进程,存在不同的页表;
- 对于相同的虚拟地址,不同的进程访问到的物理地址不同;
- 将虚拟地址转换为物理地址时,需要根据$MMU$中的页表基地址寄存器获取当前进程对应的页表基地址;
- 再根据$VPN$获取页表项地址$PTEA$,由此访问主存中的页表得到页表项;
- 当页表项的$Valid$为$1$时,表明要访问的页在内存中,则可得到主存中的物理页号$PPN$,与页内偏移组合后得到物理地址$PA$;
- 当页表项的$Valid$为$0$时,表明要访问的页不在内存中,则需要调用缺页中断处理程序,将外存中的页调入到主存中,并更新页表。
②虚拟地址$\rightarrow$物理地址(页命中)
- $CPU$给出虚拟地址$VA$
- $MMU$根据页表基地址寄存器和虚拟页号$VPN$,得到页表项地址$PTEA$;
- 根据页表项地址在内存中找到页表项$PTA$返回给$MMU$;
- $MMU$根据$PTA$中给出的$PPN$和页内偏移$VPO$,得到物理地址$PA$;
- 根据$PA$访问存储器返回数据给$CPU$;
- 其中操作$2)$和$3)$均进行访存操作。
③虚拟地址$\rightarrow$物理地址(缺页)
- $CPU$给出虚拟地址$VA$
- $MMU$根据页表基地址寄存器和虚拟页号$VPN$,得到页表项地址$PTEA$;
- 根据页表项地址在内存中找到页表项$PTA$返回给$MMU$;
- $MMU$根据$PTA$中的$Valid$位发现缺页,抛出异常,执行缺页异常处理程序;
- 如果页表已满,需要调出页后再从磁盘调入页到主存中,并更新页表;
- $cache$可以采用写穿策略,而页表总是采用写回策略,这是因为写穿策略需要同时写快存与慢存,而写磁盘比写主存慢得多。
- 返回到第一步重新进行操作。
④包含$cache$的虚存-主存层次结构
- 将主存与$cache$拆分开来,由于$cache$会缓存主存中经常访问的数据,因此部分页表块会被作为热数据调度到cache中
- 首先根据$MMU$生成的$PTEA$访问$cache$,如果页表项$PTE$命中,则直接返回$PTE$生成物理地址访问数据
- 如果访问$cache$时,页表项缺失,需要将$PTE$所在页表块从主存调度到$cache$中
- 使用$PA$访问$cache$时,也可能存在$cache$缺失问题,这时需要根据$cache$工作原理调度数据块到$cache$中
⑤快表$TLB$
- 普通情况下,地址转换速度慢
- 访问页表,访问数据,需$2$次访存,速度慢
- 为缩小页表大小,$OS$普遍采用多级页表结构,速度更慢
- $cache$虽然可以缓存部分页表块,但这种数据块的粒度较大,不能充分利用局部性
- 引入一个体积小的快表$TLB$
- 本质上是容量较小的$cache$
- 引入相联存储器机制,提高查找速度
- 采用随机替换算法
- 缓存页表中经常被访问的表项——$(Valid,VPN,PPN)$
⑥包含$TLB$表时的虚-实转换流程
⑦详细的虚-实转换流程
如图所示,最快的访问流程为最左侧直线型访问流程,此时访问性能最优
$CPU$给出虚拟地址$VA$
使用$VA$访问$TLB$,如果$TLB$命中,得到$PPN$,进而得到物理地址访问数据
- 首先使用物理地址访问$cache$,如果命中返回数据
- 如果缺失,则进行$cache$缺失处理
如果$TLB$缺失,则使用$MMU$根据$VA$生成的$PTEA$访问$cache$中的页表块
- 如果$cache$页表块命中,则得到$PTE$
- 如果$cache$页表块缺失,则使用$PTEA$访问主存页表得到$PTE$
得到$PTE$后,由有效位判断是否页命中
- 如果页命中,根据$PPN$更新$TLB$表项,使用物理地址访问$cache$
- 如果页缺失,调用缺页异常处理程序,载入页到主存中,更新$TLB$,重启缺页命令
具体的$TLB$命中、$cache$数据块命中、页命中组合如下表
序号 $TLB$ $cache$数据块 页 可能性 说明 1 命中 命中 命中 可能 $TLB$命中,则页一定命中,此时$cache$可能缺失,也可能命中 2 命中 缺失 命中 可能 同情况$1$ 3 缺失 命中 命中 可能 $TLB$缺失后还可以访问慢速页表,页可能命中,$cache$原因同情况$1$ 4 缺失 缺失 命中 可能 同情况$3$ 5 缺失 缺失 缺失 可能 最糟糕的情况,虚存系统初始化时常见 6 命中 缺失 缺失 不可能 页不在主存中,$TLB$一定不包含其页表项,$TLB$不可能命中 7 命中 命中 缺失 不可能 同情况$6$ 8 缺失 命中 缺失 不可能 页不在主存中,对应数据也不可能在$cache$中,$cache$不可能命中