- 浏览: 17534 次
最新评论
高端内存
2010年10月21日
:本文提及的物理地址 空间可以理解为就是物理内存 ,但是在某些情况下,把他们理解为物理内存是不对的。
本文讨论的环境是NON-PAE的i386平台,内核 版本2.6.31-14
一. 什么是高端内存
linux 中内核使用3G-4G的线性地址空间,也就是说总共只有1G的地址空间可以用来映射物理地址空间。但是,如果内存大于1G的情况下呢?是不是超过1G的内存 就无法使用了呢?为此内核引入了一个高端内存的概念,把1G的线性地址空间划分为两部分:小于896M物理地址空间的称之为低端内存,这部分内存的物理地 址和3G开始的线性地址是一一对应映射的,也就是说内核使用的线性地址空间3G--(3G+896M)和物理地址空间0-896M一一对应;剩下的 128M的线性空间用来映射剩下的大于896M的物理地址空间,这也就是我们通常说的高端内存区。
所谓的建立高端内存的映射就是能用一个线性地址来访问高端内存的页。如何理解这句话呢?在开启分页后,我们要访问一个物理内存地址,需要经过MMU的转换,也就是一个32位地址vaddr的高10位用来查找该vaddr所在页目录 项,用12-21位来查找页表项,再用0-11位偏移和页的起始物理地址相加得到paddr,再把该paddr放到前端总线上,那么我们就可以访问该vaddr对应的物理内存了。在低端内存中,每一个物理内存页在系统 初始化的时候都已经存在这样一个映射了。而高端内存还不存在这样一个映射(页目录项,页表都是空的 ), 所以我们必须要在系统初始化完后,提供一系列的函数来实现这个功能,这就是所谓的高端内存的映射。那么我们为什么不再系统初始化的时候把所有的内存映射都 建立好呢?主要原因是,内核线性地址空间不足以容纳所有的物理地址空间(1G的内核线性地址空间和最多可达4G的物理地址空间),所以才需要预留一部分 (128M)的线性地址空间来动态 的映射所有的物理地址空间,于是就产生了所谓的高端内存映射。
二.内核如何管理高端内存
上面的图展示了内核如何使用3G-4G的线性地址空间,首先解释下什么是high_memory
在arch/x86/mm/init_32.c里面由如下代码: # ifdef CONFIG_HIGHMEM highstart_pfn = highend_pfn = max_pfn; if (max_pfn > max_low_pfn) highstart_pfn = max_low_pfn; e820_register_active_regions( 0, 0, highend_pfn) ; sparse_memory_present_with_active_regions( 0) ; printk( KERN_NOTICE "%ldMB HIGHMEM available.\n" , pages_to_mb( highend_pfn - highstart_pfn) ) ; num_physpages = highend_pfn; high_memory = (void *) __va(highstart_pfn * PAGE_SIZE-1 )+1 ; # else e820_register_active_regions( 0, 0, max_low_pfn) ; sparse_memory_present_with_active_regions( 0) ; num_physpages = max_low_pfn; high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1)+ 1 ; # endif high_memory是"具体物理内存的上限对应的虚拟 地址",可以这么理解:
当内存内存小于896M时,那么high_memory = (void *) __va(max_low_pfn * PAGE_SIZE),max_low_pfn就是在内存中最后的一个页帧号,所以high_memory=0xc0000000+物理内存大小;
当内存大于896M时,那么 highstart_pfn = max_low_pfn, 此时max_low_pfn就不是物理内存的最后一个页帧号了,而是内存为896M时的最后一个页帧号,那么 high_memory=0xc0000000+896M.总之high_memory是不能超过0xc0000000+896M.
由于我们讨论的是物理内存大于896M的情况,所以high_memory实际上就是0xc0000000+896M,从high_memory开始的128M(4G-high_memory)就是用作用来映射剩下的大于896M的内存的,当然这128M还可以用来映射设备 的内存(MMIO)。
从 上图我们看到有VMALLOC_START,VMALLOC_END,PKMAP_BASE,FIX_ADDRESS_S TART等宏术语,其实这些术语 划分了这128M的线性空间,一共分为三个区域:VMALLOC区域(本文不涉及这部分内容,关注本博客的其他文章),永久映射区(permanetkernel mappings), 临时映射区(temporary kernel mappings).这三个区域都可以用来映射高端内存,本文重点阐述下后两个区域是如何映射高端内存的。
三. 永久映射区(permanet kernel mappings)
1. 介绍几个定义:
PKMAP_BASE :永久映射区的起始线性地址。
pkmap_page_table :永久内核映射允许内核建立高端页框到内核地址空间的长期映射,它们使用主内核页表中一个专门的页表,其地址存放在
pkmap_page_table 。
LAST_PKMAP :pkmap_page_table里面包含的entry的数量=1024 或512,取决于PAE是否激活。
pkmap_count[LAST_PKMAP]数组:每一个元素的值对应一个entry的引用计数。关于引用计数的值,有以下几种情况:
0:说明这个entry可用。
1:语义特殊,表示该位置的页已经映射,但由于CPU的TLB没有更新而无法使用,见下面的情景。
N:有N-1个对象正在使用这个页面
首先,要知道这个区域的大小是4M,也就是说128M的线性地址空间里面,只有4M的线性地址空间是用来作永久映射区的。至于到底是哪4M,是由PKMAP_BASE决定的,这个变量表示用来作永久内存映射的4M区间的起始线性地址。(如果启动PAE,则只有2M)
在NON-PAE的i386上,页目录里面的每一项都指向一个4M的空间,所以永久映射区只需要一个页目录项就可以了。而一个页目录项指向一张页表,那么永久映射区正好就可以用一张页表来表示了,于是我们就用pkmap_page_table来指向这张页表。 pgd = swapper_pg_dir + pgd_index( vaddr) ; pud = pud_offset( pgd, vaddr) ;//pud==pgd pmd = pmd_offset( pud, vaddr) ;//pmd==pud==pgd pte = pte_offset_kernel( pmd, vaddr) ; pkmap_page_table = pte; 2. 具体代码分析(2.6.31) void * kmap( struct page * page) { might_sleep( ) ; if ( ! PageHighMem( page) ) return page_address( page) ; return kmap_high( page) ; } kmap()函数就是用来建立永久映射的函数 :由于调用kmap函数有可能会导致进程 阻塞,所 以它不能在中断处理函数等不可被阻塞的上下文下被调用, might_sleep()的作用就是当该函数在不可阻塞的上下文下被调用是,打印栈信息。
接下来判断该需要建立永久映射的页是否确实属于高端内存,因为我们知道低端内存的每个页都已经存在和线性地址的映射了,所以,就不需要再建立 了,page_address()函数返回该page对应的线性地址。(关于page_address()函数,参考本博客的专门文章有解释)。最后调用 kmap_high(page),可见kmap_high()才真正执行建立永久映射的操作。 /** * kmap_high - map a highmem page into memory * @page: &struct page to map * * Returns the page's virtual memory address. * * We cannot call this from interrupts, as it may block. */ void * kmap_high( struct page * page) { unsigned long vaddr; /* * For highmem pages, we can't trust "virtual" until * after we have the lock. */ lock_kmap( ) ; vaddr = ( unsigned long ) page_address( page) ; if ( ! vaddr) vaddr = map_new_virtual( page) ; pkmap_count[ PKMAP_NR( vaddr) ] + + ; BUG_ON( pkmap_count[ PKMAP_NR( vaddr) ] 代码在这个函数里面
static inline unsigned long map_new_virtual( struct page * page) { unsigned long vaddr; int count ; start: count = LAST_PKMAP;//LAST_PKMAP=1024 /* Find an empty entry */ for ( ; ; ) { last_pkmap_nr = ( last_pkmap_nr + 1) & LAST_PKMAP_MASK; if ( ! last_pkmap_nr) { flush_all_zero_pkmaps( ) ; count = LAST_PKMAP; } if ( ! pkmap_count[ last_pkmap_nr] ) break ; /* Found a usable entry */ if ( - - count ) continue ; /* * Sleep for somebody else to unmap their entries */ { DECLARE_WAITQUEUE( wait, current) ; __set_current_state( TASK_UNINTERRUPTIBLE) ; add_wait_queue( & pkmap_map_wait, & wait) ; unlock_kmap( ) ; schedule( ) ; remove_wait_queue( & pkmap_map_wait, & wait) ; lock_kmap( ) ; /* Somebody else might have mapped it while we slept */ if ( page_address( page) ) return ( unsigned long ) page_address( page) ; /* Re-start */ goto start; } } vaddr = PKMAP_ADDR( last_pkmap_nr) ; set_pte_at( & init_mm, vaddr, & ( pkmap_page_table[ last_pkmap_nr] ) , mk_pte( page, kmap_prot) ) ; pkmap_count[ last_pkmap_nr] = 1; set_page_address( page, ( void * ) vaddr) ; return vaddr; }
10 last_pkmap_nr 是全局变量,记录最后使用的位置,该行使 last_pkmap_nr曾1,
当到达pkmap_count的最大索引值 LAST_PKMAP时,搜索绕回到位置0继续.这就
实现了所谓的反向扫描pkmap_count数组。并且在绕回到位置0时顺便执行
flush_all_zero_pkmaps()来刷出CPU高速缓存,但尚未更新TLB。
15 pkmap_count[ last_pkmap_nr]=0,说明我们找到了一个位置,可以使用的。
17 执行到这里,说明我们还没找到,如果--count不为0,说明还没有搜索完一整圈,继续
搜索。如果为0,说明已经搜索了一整圈了,还没找到合适的位置。
23~37 该流程进入睡眠状态,其中33~34是希望睡眠期间有其他哥们已经帮我把page映射了。
如果没有则跳到start处再重新执行搜索过程。直到找到为止。
39 终于找到了一个位置,通过PKMAP_ADDR计算出该位置处的虚拟地址
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) 内存映射中我们看到,如果pkmap_page_table页表里面没有空的entry,那么就会导致这次映射被阻塞,所以我们说不能在一些原子的上下文情况下调用kmap()函数。而在临时内存映射中,不会去判断该pte是否已经被用掉了,它采用的是覆盖的策略,所以把总是能成功的建立映射。会不会被阻塞就是临时内存映射和永久内存映射一个最明显的区别。
enum fixed_addresses {
#ifdef CONFIG_X86_32
FIX_HOLE,
FIX_VDSO,
#else
VSYSCALL_LAST_PAGE,
VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE
+(( VSYSCALL_END- VSYSCALL_START)>> PAGE_SHIFT)- 1,
VSYSCALL_HPET,
#endif
FIX_DBGP_BASE,
FIX_EARLYCON_MEM_BASE,
#ifdef CONFIG_X86_LOCAL_APIC
FIX_APIC_BASE,/* local (CPU) APIC) -- required for SMP or not */
#endif
#ifdef CONFIG_X86_IO_APIC
FIX_IO_APIC_BASE_0,
FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,
#endif
#ifdef CONFIG_X86_VISWS_APIC
FIX_CO_CPU,/* Cobalt timer */
FIX_CO_APIC,/* Cobalt APIC Redirection Table */
FIX_LI_PCIA,/* Lithium PCI Bridge A */
FIX_LI_PCIB,/* Lithium PCI Bridge B */
#endif
#ifdef CONFIG_X86_F00F_BUG
FIX_F00F_IDT,/* Virtual mapping for IDT */
#endif
#ifdef CONFIG_X86_CYCLONE_TIMER
FIX_CYCLONE_TIMER,/*cyclone timer register*/
#endif
#ifdef CONFIG_X86_32
FIX_KMAP_BEGIN,/* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN+( KM_TYPE_NR* NR_CPUS)- 1,
#ifdef CONFIG_PCI_MMCONFIG
FIX_PCIE_MCFG,
#endif
#endif
#ifdef CONFIG_PARAVIRT
FIX_PARAVIRT_BOOTMAP,
#endif
FIX_TEXT_POKE1,/* reserve 2 pages for text_poke() */
FIX_TEXT_POKE0,/* first page is last, because allocation is backward */
__end_of_permanent_fixed_addresses,
/*
* 256 temporary boot-time mappings, used by early_ioremap(),
* before ioremap() is functional.
*
* We round it up to the next 256 pages boundary so that we
* can have a single pgd entry and a single pte table:
*/
#define NR_FIX_BTMAPS 64
#define FIX_BTMAPS_SLOTS 4
FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
( __end_of_permanent_fixed_addresses & 255),
FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS* FIX_BTMAPS_SLOTS - 1,
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
FIX_OHCI1394_BASE,
#endif
#ifdef CONFIG_X86_32
FIX_WP_TEST,
#endif
#ifdef CONFIG_INTEL_TXT
FIX_TBOOT_BASE,
#endif
__end_of_fixed_addresses
};
从FIXADDR_START到FIXADDR_TOP这段地址空间被称为固定映射线性空间,这段地址空间主要用来映射一些设备的内存和寄存器,像FIX_APIC_BASE是用来映射local apic的寄存器的。其中的FIX_KMAP_BEGIN到FIX_KMAP_END是用来供临时内存映射的使用。 这段空间的大小是KM_TYPE_NR* NR_CPUS,也就是说,每个CPU都有独立的KM_TYPE_NR大小的空间,来看看看KM_TYPE_NR是什么
#ifdef __WITH_KM_FENCE
#define KMAP_D( n) __KM_FENCE_## n ,
#else
#define KMAP_D( n)
#endif
enum km_type {
KMAP_D( 0) KM_BOUNCE_READ,
KMAP_D( 1) KM_SKB_SUNRPC_DATA,
KMAP_D( 2) KM_SKB_DATA_SOFTIRQ,
KMAP_D( 3) KM_USER0,
KMAP_D( 4) KM_USER1,
KMAP_D( 5) KM_BIO_SRC_IRQ,
KMAP_D( 6) KM_BIO_DST_IRQ,
KMAP_D( 7) KM_PTE0,
KMAP_D( KM_PTE1,
KMAP_D( 9) KM_IRQ0,
KMAP_D( 10) KM_IRQ1,
KMAP_D( 11) KM_SOFTIRQ0,
KMAP_D( 12) KM_SOFTIRQ1,
KMAP_D( 13) KM_SYNC_ICACHE,
KMAP_D( 14) KM_SYNC_DCACHE,
/* UML specific, for copy_*_user - used in do_op_one_page */
KMAP_D( 15) KM_UML_USERCOPY,
KMAP_D( 16) KM_IRQ_PTE,
KMAP_D( 17) KM_NMI,
KMAP_D( 18) KM_NMI_PTE,
KMAP_D( 19) KM_TYPE_NR
};
每个枚举项都代表了一个pte,每个CPU都有20个这样的pte供临时内核映射使用。我们先来看看内核如何来获得这些对应的枚举项所对应的pte地址: 这个宏返回的是固定线性映射里面枚举项所对应的线性地址,FIXADDR_TOP=0xfffff000,以FIX_APIC_BASE为例,__fix_to_virt(FIX_APIC_BASE),FIX_APIC_BASE等于4,那么他的线性地址就是0xfffff000-(4代码是完整的如何通过枚举项,获得对应的pte项所对应的线性地址。
staticinline pte_t * kmap_get_fixmap_pte(unsignedlong vaddr)
{
return pte_offset_kernel( pmd_offset( pud_offset( pgd_offset_k( vaddr), vaddr), vaddr), vaddr);
}
staticvoid __init kmap_init(void)
{
unsignedlong kmap_vstart;
/*
* Cache the first kmap pte:
*/
kmap_vstart = __fix_to_virt( FIX_KMAP_BEGIN);
kmap_pte = kmap_get_fixmap_pte( kmap_vstart);
kmap_prot = PAGE_KERNEL;
}
注意:kmap_pte是临时内存映射起始的页表项,接下来的其他页表项根据他们的相对位置差就可以求得。比如idx对应的pte=kmap_pte - idx,为什么是减不是加,看上面的说明(越靠前的枚举项对应的线性地址越靠后 )。 /*
* kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
* no global lock is needed and because the kmap code must perform a global TLB
* invalidation when the kmap pool wraps.
*
* However when holding an atomic kmap it is not legal to sleep, so atomic
* kmaps are appropriate for short, tight code paths only.
*/
void* kmap_atomic_prot(struct page * page,enum km_type type, pgprot_t prot)
{
enum fixed_addresses idx;
unsignedlong vaddr;
/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
pagefault_disable();
//判断要建立映射的页在高端内存中,否则其线性地址已经存在
if(! PageHighMem( page))
return page_address( page);
debug_kmap_atomic( type);
//求得对应的idx
idx = type + KM_TYPE_NR* smp_processor_id(); //内核可以访问该页的线性地址
vaddr = __fix_to_virt( FIX_KMAP_BEGIN + idx);
BUG_ON(! pte_none(*( kmap_pte- idx))); //根据kmap_pte,建立对应的页表项映射,之后就可以通过vaddr访问该页了
set_pte( kmap_pte- idx, mk_pte( page, prot));
return(void*) vaddr;
}
void* kmap_atomic(struct page * page,enum km_type type)
{
return kmap_atomic_prot( page, type, kmap_prot);
}
解除映射也很简单,没有做什么特殊处理: void kunmap_atomic(void* kvaddr,enum km_type type)
{
unsignedlong vaddr =(unsignedlong) kvaddr & PAGE_MASK;
enum fixed_addresses idx = type + KM_TYPE_NR* smp_processor_id();
/*
* Force other mappings to Oops if they'll try to access this pte
* without first remap it. Keeping stale mappings around is a bad idea
* also, in case the page changes cacheability attributes or becomes
* a protected page in a hypervisor.
*/
if( vaddr == __fix_to_virt( FIX_KMAP_BEGIN+ idx))
kpte_clear_flush( kmap_pte- idx, vaddr);
else{
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON( vaddr =(unsignedlong) high_memory);
#endif
}
pagefault_enable();
}
发表评论
-
Linux的mmap文件内存映射机制
2012-01-20 08:13 664Linux的mmap文件内存映射 ... -
windows内存管理
2012-01-20 08:13 680windows内存管理 2010年07 ... -
2--共享内存的实践到内核--共享内存的映射
2012-01-20 08:13 8212--共享内存的实践到内核--共享内存的映射 2011年05 ... -
内核同步机制-优化屏障和内存屏障
2012-01-20 08:13 661内核同步机制-优化屏障和内存屏障 2011年01月07日 ... -
使用脚本程序管理Windows网络(9)
2012-01-19 13:30 643使用脚本程序管理Windows ... -
开机快速自动联网(一句话的VBS)
2012-01-19 13:30 784开机快速自动联网(一句话的VBS) 2010年10月20日 ... -
使用脚本程序管理Windows网络(3)
2012-01-19 13:30 677使用脚本程序管理Windows ... -
VBS WScript.Shell 隐藏cmd命令行
2012-01-19 13:30 1203VBS WScript.Shell 隐藏cmd命令行 201 ... -
全自动申请qq号vbs代码
2012-01-19 13:29 866全自动申请qq号vbs代码 2011年08月25日 下面 ... -
Windows Server 2003中 w3wp.exe 占用cpu 100% 资源的解决方法
2012-01-17 03:19 1102Windows Server 2003中 w3wp.exe 占 ... -
内存不能为读的原因以及解决方法
2012-01-17 03:19 602内存不能为读的原因以及解决方法 2010年11月22日 ... -
i9001
2012-01-17 03:19 713i9001 2011年12月13日 一、外观检查,外壳、 ... -
Unnamed System Edition v4.0
2012-01-17 03:19 781Unnamed System Edition v4.0 20 ... -
安全bios手册(2)
2012-01-17 03:19 519安全bios手册(2) 2010年06月20日 BIOS ... -
中国各地人的长相特征
2012-01-16 01:53 1151中国各地人的长相特征 ... -
大雪话节气
2012-01-16 01:53 535大雪话节气 2011年12月07 ... -
有妇如此,夫复何求!
2012-01-16 01:53 1094有妇如此,夫复何求! 201 ... -
网络情缘
2012-01-16 01:53 489网络情缘 2011年12月12日 ... -
表格选择
2012-01-11 01:50 470表格选择 2011年08月01日 1.给表格的奇数行添 ... -
Ajax应用
2012-01-11 01:50 552Ajax应用 2011年08月01日 一. 正规的Aj ...
相关推荐
)描述了高端内存原理和源码注释详解,能够清楚的理解什么是高端内存,什么是vmalloc,什么是永久映射,什么是临时映射,需要注意什么,应用场合是怎样,在源码中的前龙后脉都有详细的注释和解释
高端内存的详解:linux用户空间与内核空间.docx
信息技术行业:澜起科技,高端内存接口芯片领先企业-0619-银河证券-16页.pdf
信息技术行业:澜起科技,高端内存接口芯片领先企业-20190619-银河证券-16页.pdf
这样,Kernel必须使用以下策略:当内核要访问高于896MB的内存时,这些内存空间被暂时映射到内核虚拟空间内核需要频繁访问的那部分内存被放到低于896MB的内
与直接映射的物理内存末端、高端内存的始端所对应的线性地址存放在high_memory变量中,在x86体系结构上,高于896MB的所有物理内存的范围大都是高端内存,它并不会地或自动地映射到内核地址空间,尽管x86处理器能够...
Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被...Linux内核高端内存的由来当内核模块代码或线程访问内存时,
从高端内存装载每一个TSR——使用一内存优化程序 ROM在缩——将一个ROM的有用部分放在一起 High RAM的终极——STEALTH 使用内存管理程序的好处 第8章 扩充内存如何工作 扩充内存的简要历史 内存映射 扩充内存象船上...
启动时只带光驱驱动,并且使用EMM386开启高端内存以节省常规内存 2. Start computer with U-Disk support only [EMM386 NOEMS]. 启动时只带U盘驱动,并且使用EMM386开启高端内存以节省常规内存 3. Start computer ...
1.7 高端内存内核映射 50 1.8.1 永久内存映射 50 1.8.2 临时内核映射 55 第二章 内核级内存管理系统 58 2.1 Linux页面管理 58 2.1.1 NUMA架构 61 2.1.2 内存管理区 62 2.2 伙伴系统算法 65 2.2.1 数据结构 66 2.2.2 ...
DDR2 SDRAM 内存JEDEC标准频率时序,高端内存超低CL延迟的参数设置
目录:页表管理 内核页表 物理内存 高端内存 地址映射 虚拟内存 地址空间 高速缓存 页框回收 交换机制 缺页异常 共享内存 文件映射 程序执行
emm386 扩展内存管理 fdisk 硬盘分区 help 帮助 label 设置卷标号 lh 将程序装入高端内存 memmaker内存优化管理 msd 系统检测 path 设置搜寻目录 prempt 设置提示符 restore 恢复备份文件 time 显示及修改时间 ...
在DOS下,系统中存在以下四种内存: 常规内存(Conventional Memory); 高端内存(Upper Memory); 扩充内存(Expanded Memory); 扩展内存(Extended Memory)。
lh/loadhigh将程序装入高端内存 memmaker内存优化管理 msd系统检测 undelete恢复被删除的文件 prompt设置提示符 restore恢复已备份的文件 time显示及修改时间 set 设置环境变量 smartdrv设置磁盘加速器 ...
是否将COMMAND.COM、Drvspace.bin、Dblspace.bin等加载到高端内存,如启动中出现内存地址冲突,可将该值设为0 这类冲突多由CONFIG.SYS、AUTOEXEC.BAT加载的程序造成Autoscan=1/0 非正常关机(如掉电等)再...
直接访问I/O设备,直接访问物理内存 源代码
产品定位于内存数据库系统和提供高端高性能系统的开发、处理平台。 Cache Server内存数据库是将所有数据加载到物理内存,不需要访问磁盘就直 接访问数据,从而获得极高的存取速度和极强的并发访问能力的数据库管理...
产品定位于内存数据库系统和提供高端高性能系统的开发、处理平台。 Cache Server内存数据库是将所有数据加载到物理内存,不需要访问磁盘就直 接访问数据,从而获得极高的存取速度和极强的并发访问能力的数据库管理...
FB-DIMM是高端内存连接使用的一种互连结构,使内存芯片能够以每秒6.4 G字节的吞吐量运行,比当前DDR-2-400模块的吞吐量翻了一番。类似的,第二代PCI Express的运行速率为5Gb/s,比当前PCI Express规范的带宽翻了一番...