硬件辅助的对象存储器迁移转让专利

申请号 : CN201580060952.5

文献号 : CN107111548A

文献日 :

基本信息:

PDF:

法律信息:

相似专利:

发明人 : Z·拉多维奇

申请人 : 甲骨文国际公司

摘要 :

用于结合处理器中的垃圾收集利用存储器版本指令和技术的系统和方法。计算系统可以执行硬件辅助的垃圾收集算法,以在存储器区域之间移动存活对象。可以利用特殊的存储指令来标记每个存储器区域的即将被迁移的存活对象。执行有用的工作的转变器可以被配置为在标记用于迁移的存储器区域上进行捕捉。

权利要求 :

1.一种计算系统,包括:

存储器;以及

耦合到所述存储器的处理器,其中作为垃圾收集过程的一部分,所述处理器被配置为:识别所述存储器的第一区域中的用于迁移的第一对象;

通过将与所述第一对象相关联的第一版本号改变为指示为对象迁移保留的值的第二版本号,标记用于从所述存储器的所述第一区域迁移到所述存储器的第二区域的所述第一对象;

在所述第一区域中的所述第一对象被迁移到所述第二区域之前,检测对所述第一对象的访问,其中所述访问包括所述第一版本号;

将所述第一版本号与所述第二版本号进行比较;

响应于检测到所述第一版本号与所述第二版本号匹配,允许对所述第一对象的所述访问;

响应于检测到所述第一版本号与所述第二版本号不匹配,停止对所述第一对象的所述访问;

将所述第一对象从所述第一区域移动到所述第二区域;以及

响应于完成所述第一对象到所述第二区域的迁移,从所述第一对象中移除所述第二版本号。

2.如权利要求1所述的计算系统,其中所述处理器包括存储队列,所述存储队列包括多个条目,其中所述多个条目中的每个条目被配置为存储以下中的至少一个或多个:线程标识符ID、版本号以及存储器损坏检测MCD启用状态,所述存储器损坏检测MCD启用状态指示对于由线程ID识别出的给定线程是否启用了MCD检查。

3.如权利要求1所述的计算系统,其中所述第一区域是被定义为存储器损坏检测MCD区域的堆区域。

4.如权利要求1所述的计算系统,其中所述处理器被配置为利用存储器损坏检测MCD存储指令来改变与所述第一对象相关联的版本号,其中MCD存储指令仅修改目标地址的版本号并且使所述目标地址的应用数据保持不变。

5.如权利要求4所述的计算系统,其中所述处理器被配置为通过检测所述访问的版本号和所述第一对象的版本号之间的失配来确定所述访问发生在所述第一对象被标记用于迁移之后。

6.如权利要求1所述的计算系统,其中为了移除所述第二版本号,所述处理器被配置为将所述第二版本号改变为所述第一版本号。

7.如权利要求1所述的计算系统,其中所述处理器还被配置为响应于在所述第一对象被标记用于迁移之后检测到所述访问而触发捕捉例程来解决依赖性。

8.一种用于处理器的方法,所述方法包括:

发起垃圾收集过程,其中所述过程包括:

识别存储器的第一区域中的用于迁移的第一对象;

通过将与所述第一对象相关联的第一版本号改变为指示为对象迁移保留的值的第二版本号,标记用于从所述存储器的所述第一区域迁移到所述存储器的第二区域的所述第一对象;

在所述第一区域中的所述第一对象被迁移到所述第二区域之前,检测对所述第一对象的访问,其中所述访问包括所述第一版本号;

将所述第一版本号与所述第二版本号进行比较;

响应于检测到所述第一版本号与所述第二版本号匹配,允许对所述第一对象的所述访问;

响应于检测到所述第一版本号与所述第二版本号不匹配,停止对所述第一对象的所述访问;

将所述第一对象从所述第一区域移动到所述第二区域;以及

响应于完成所述第一对象到所述第二区域的迁移,从所述第一对象中去除所述第二版本号。

9.如权利要求8所述的方法,还包括在存储队列的多个条目中的每个条目中存储以下中的至少一个或多个:线程标识符ID、版本号以及存储器损坏检测MCD启用状态,所述存储器损坏检测MCD启用状态指示对于由线程ID识别出的给定线程是否启用了MCD检查。

10.如权利要求9所述的方法,其中所述第一区域是被定义为存储器损坏检测MCD区域的堆区域。

11.如权利要求8所述的方法,还包括利用存储器损坏检测MCD存储指令来改变与所述第一对象相关联的版本号,其中MCD存储指令仅修改目标地址的版本号并且使所述目标地址的应用数据保持不变。

12.如权利要求11所述的方法,还包括通过检测所述访问的版本号和所述第一对象的版本号之间的失配来确定所述访问发生在所述第一对象被标记用于迁移之后。

13.如权利要求11所述的方法,其中为了移除所述第二版本号,所述方法还包括响应于将所述第一对象从所述第一区域移动到所述第二区域而将所述第二版本号改变为所述第一版本号。

14.如权利要求8所述的方法,还包括响应于在所述第一对象被标记用于迁移之后检测到所述访问而触发捕捉例程来解决依赖性。

15.一种处理器,被配置为:

执行垃圾收集,其中为了执行所述垃圾收集,所述处理器被配置为:识别存储器的第一区域中的用于迁移的第一对象;

通过将与所述第一对象相关联的第一版本号改变为指示为对象迁移保留的值的第二版本号,标记用于从所述存储器的所述第一区域迁移到所述存储器的第二区域的所述第一对象;

在所述第一区域中的所述第一对象被迁移到所述第二区域之前,检测对所述第一对象的访问,其中所述访问包括所述第一版本号;

将所述第一版本号与所述第二版本号进行比较;

响应于检测到所述第一版本号与所述第二版本号匹配,允许对所述第一对象的所述访问;

响应于检测到所述第一版本号与所述第二版本号不匹配,停止对所述第一对象的所述访问;

将所述第一对象从所述第一区域移动到所述第二区域;以及

响应于完成所述第一对象到所述第二区域的迁移,从所述第一对象中去除所述第二版本号。

16.如权利要求15所述的处理器,其中所述处理器包括存储队列,所述存储队列包括多个条目,其中所述多个条目中的每个条目被配置为存储以下中的至少一个或多个:线程标识符ID、版本号以及存储器损坏检测MCD启用状态,所述存储器损坏检测MCD启用状态指示对于由线程ID识别出的给定线程是否启用了MCD检查。

17.如权利要求16所述的处理器,其中所述第一区域是被定义为存储器损坏检测MCD区域的堆区域。

18.如权利要求15所述的处理器,其中所述处理器还被配置为利用存储器损坏检测MCD存储指令来改变与所述第一对象相关联的版本号,其中MCD存储指令仅修改目标地址的版本号并且使所述目标地址的应用数据保持不变。

19.如权利要求18所述的处理器,其中所述处理器还被配置为通过检测所述访问的版本号和所述第一对象的版本号之间的失配来确定所述访问发生在所述第一对象被标记用于迁移之后。

20.如权利要求18所述的处理器,其中为了移除所述第二版本号,所述处理器还被配置为响应于将所述第一对象从所述第一区域移动到所述第二区域而将所述第二版本号改变为所述第一版本号。

说明书 :

硬件辅助的对象存储器迁移

[0001] 本发明的背景

技术领域

[0002] 本发明涉及计算系统,并且更具体地,涉及使用已经被知晓为“垃圾收集”的技术的计算机系统的存储器管理。

背景技术

[0003] 在计算机系统领域中,在分配和管理存储器的任务上已经付出了相当大的努力。通常,存储器可以被静态地或动态地分配给数据对象(数据对象也可以被称为数据结构或记录)。一些计算机语言可能要求为程序中定义的所有变量静态地(例如在编译时)分配存储器。这种静态存储器分配可能使得难以在多个应用之间共享可用的存储器空间,尤其是对于长期存活的应用。当平台提供对动态存储器分配的支持时,例如当要分配给给定对象的存储器空间仅在运行时才确定时,遵守空间限制可能更容易。
[0004] 动态分配相对于静态分配具有许多优点。一个这样的优点是运行时系统能够使分配适于运行时条件。例如,程序员可以指定仅响应于特定运行时条件才为给定对象分配空间。C语言库函数malloc()和C++操作符new可以用于此目的。相反,程序员可以指定先前分配给给定对象的存储器可以被回收以用于重用的条件。C语言库函数free()和C++操作符delete导致这种存储器回收。因为动态分配提供了存储器重用,因此它便于生成大型或长期存活的应用,这些应用在其生命周期过程中可以采用对象,如果这些对象被静态绑定到存储器位置,那么这些对象的总存储器需求将大大超过可用的存储器资源。
[0005] 然而,必须小心地执行动态存储器的分配和回收,尤其是对于长期存活的应用。如果应用无法回收未使用的存储器——或者更糟的是,丢失了对动态分配的存储器段的地址的跟踪——那么该应用的存储器需求可能随时间增长而超过系统的可用存储器。这种错误被知晓为“存储器泄漏”。当即使应用仍然维持对存储器的引用该应用也回收该存储器以用于重用时,会发生另一种错误。如果回收的存储器被重新分配用于不同目的,那么该应用可能不经意地以多种不一致的方式操纵同一存储器。这种错误被知晓为“悬空引用(dangling reference)”。
[0006] 减少这种泄漏和相关错误的可能性的方式是以更自动的方式提供存储器空间回收。由系统使用的自动回收存储器空间的技术通常被称为垃圾收集。垃圾收集器通过回收它们不再认为是“存活”或“可达”的空间来操作(不可达的空间可以称为“垃圾”,这是本技术的名称来由)。由程序的全局变量表示的静态分配的对象一般被认为贯穿程序的生命周期是可达的。这样的对象通常不存储在垃圾收集器的受管理的存储器空间(例如,堆)中,但是它们可以包含对存储在垃圾收集器的受管理的存储器空间中的动态分配的对象的引用,并且这样的存储在垃圾收集器的受管理的存储器空间中的动态分配的对象被认为是可达的。显然,在处理器的调用栈中引用的对象是可达的,由寄存器内容引用的对象也是可达的。由任何可达对象引用的对象也是可达的。
[0007] 垃圾收集器的使用是有利的,这是因为虽然针对特定代码序列工作的程序员在任何给定时间仅使用应用的局部知识就可以在大多数方面可靠地执行该程序员的任务,但是存储器分配和回收需要该程序的全局知识。具体而言,处理给定代码序列的程序员确实往往知道存储器的某个部分是否仍然被用于该代码序列,但是他很难知道应用的其余部分正在对该存储器做什么。通过追踪来自根集合的一些保守概念(例如,全局变量、寄存器和调用栈)的引用,自动垃圾收集器以有条理(methodical)的方式获得全局知识。通过使用垃圾收集器,程序员不用再担心应用的全局状态并且可以专注于更易于管理的局部状态问题。结果是更健壮的、没有悬空引用并且具有更少存储器泄漏的应用。
[0008] 鉴于以上情况,期望用于执行垃圾收集的高效方法和机制。

发明内容

[0009] 设想了用于结合垃圾收集利用存储器版本指令和技术的系统和方法。
[0010] 在一个实施例中,在由计算系统执行计算机程序期间,在物理存储器中分配的数据对象可以与版本号相关联。在一个实施例中,可以初始化JavaTM虚拟机(JVM),使得在对象被管理的堆区域上启用存储器版本控制(versioning)。(Java是Oracle和/或其附属公司的商标或注册商标)。可以使用操作系统(OS)调用来通知OS关于哪个虚拟地址(VA)空间应当被管理为存储器损坏检测(MCD)区域。
[0011] 在一个实施例中,硬件辅助的垃圾收集算法可以由计算系统执行以将存活对象(live object)从一个或多个存储器区域移动到另一个“清洁”区域。当对象正在被迁移时,该对象可以以紧凑的格式存储在新的“清洁”区域中以使存储器碎片最少。在一个实施例中,垃圾收集算法可以通过执行使用JVM级加载/存储指令的存活集合标记以标记每个存储器区域的即将被迁移的存活集合来完全绕过OS。垃圾收集算法可以启用与应用堆大小相一致的并发和连续的细粒度对象迁移,使得Java应用线程(或转变器(mutator))可以在对象正被迁移的同时取得进展。为了将程序中的做“有用的”工作的部分与进行垃圾收集的部分区分开来,术语转变器有时用于“有用的”部分。此外,垃圾收集算法也可以允许在巨大的存储器页面内完成垃圾收集标记。
[0012] 在一个实施例中,可以在计算系统中利用每线程的检查控制。可以为每个转变器线程启用MCD检查。在各个实施例中,可以存在用于每个运行线程的硬件(HW)控制寄存器(例如,由OS/管理程序(HV)管理)。在一个实施例中,即将把存活对象的集合从一个存储器区域迁移到另一个存储器区域的垃圾收集线程可以发出具有特殊/保留的MCD值的存储,使得转变器可以在该堆的那个“标记用于迁移的存活集合”的区域上进行捕捉(trap)。可以利用只存储存储器版本并使应用数据保持不变的特殊存储指令。当堆区域被定义为“MCD区域”时,可以使用MCD存储指令翻转(flip)存活对象的存储器版本信息,以避免任何OS/HV应用程序接口(API)开销。在一个实施例中,单个存储器版本值可以被保留并且被用于将被考虑用于迁移的对象标记为“已迁移或即将迁移”。在其它实施例中,多个值可以被保留并且被用于标记用于迁移的对象。
[0013] 当参考以下描述和附图时,这些实施例和其它实施例将变得明显。

附图说明

[0014] 图1是示出计算系统的一个实施例的一般化框图。
[0015] 图2是示出进程地址空间的一个实施例的一般化框图。
[0016] 图3是示出存储器访问地址格式的一个实施例的一般化框图。
[0017] 图4是示出用于版本号失配(mismatch)的真值表的一个实施例的一般化框图。
[0018] 图5是示出存储器接口的一个实施例的一般化框图,该存储器接口示出存储器请求的不同来源。
[0019] 图6是示出用于初始化具有版本号的数组的方法的一个实施例的一般化流程图。
[0020] 图7是示出用于执行具有版本号的存储器访问操作的方法的一个实施例的一般化框图。
[0021] 图8是示出用于执行更新版本号的存储器访问操作的方法的一个实施例的一般化流程图。
[0022] 图9是用于执行更新版本号的存储器访问操作的方法的另一个实施例。
[0023] 图10是示出用于执行硬件辅助的细粒度对象存储器迁移的方法的一个实施例的一般化流程图。
[0024] 图11是示出用于将对象从一个存储器位置迁移到另一个存储器位置的方法的一个实施例的一般化流程图。
[0025] 图12是示出用于迁移存活对象的方法的一个实施例的一般化流程图。
[0026] 虽然本文所述的方法和机制可以有各种修改和替代形式,但是在附图中通过示例的方式示出并在本文中详细描述了具体的实施例。然而,应当理解,附图及对附图的详细描述并不旨在将本发明限制于所公开的特定形式,而是相反地旨在覆盖一旦本公开被完全理解就对本领域技术人员明显的所有修改、等同物和替代方案。

具体实施方式

[0027] 在以下描述中,阐述了许多具体细节以提供对本文呈现的方法和机制的透彻理解。然而,本领域普通技术人员应该认识到,各个实施例可以在没有这些具体细节的情况下实践。在一些实例中,众所周知的结构、组件、信号、计算机程序指令和技术未详细示出,以避免模糊本文描述的方法。将认识到的是,为了说明的简单和清楚,图中所示的元素不一定按比例绘制。例如,可以相对于其它元素夸大一些元素的尺寸。
[0028] 本说明书包括对“一个实施例”的引用。短语“在一个实施例中”在不同上下文中的出现并不一定指同一实施例。可以以与本公开一致的任何合适方式组合特定的特征、结构或特性。此外,如贯穿本申请所使用的,词语“可以”在许可的意义(即,意味着有可能)而不是强制的意义(即,意味着必须)上使用。类似地,词语“包括”意味着包括但不限于。
[0029] 术语。以下段落提供用于在本公开(包括所附权利要求)中找到的术语的定义和/或上下文:
[0030] “包括”。这个术语是开放式的。如所附权利要求中所使用的,该术语不排除附加的结构或步骤。考虑记载了“计算机系统包括物理存储器...”的权利要求。这样的权利要求不会使计算系统排除包括附加组件(例如,高速缓存、存储器控制器)。
[0031] “配置为”。各种单元、电路或其它组件可以被描述或被请求保护为“配置为”执行一个或多个任务。在这种上下文中,“配置为”用于通过指示单元/电路/组件包括在操作期间执行一个或多个任务的结构(例如,电路系统)来隐含结构。由此,即使当指定的单元/电路/组件当前不操作(例如,没有开启)时,也可以说该单元/电路/组件被配置为执行任务。与“配置为”语言一起使用的单元/电路/组件包括硬件——例如,电路、存储可执行以实现操作的程序指令的存储器,等等。单元/电路/组件被“配置为”执行一个或多个任务的记载明确地不是对该单元/电路/组件援引35U.S.C§112,段(f)。此外,“配置为”可以包括由软件和/或固件(例如,执行软件的通用处理器或FPGA)操纵而以能够执行所讨论的(一个或多个)任务的方式操作的通用结构(例如,通用电路系统)。“配置为”还可以包括使制造过程(例如,半导体制造设施)适合于制造适于实现或执行一个或多个任务的设备(例如,集成电路)。
[0032] “基于”。如本文所使用的,该术语用于描述影响确定的一个或多个因素。这个术语不排除可以影响确定的附加因素。即,确定可能仅仅基于那些因素,或者至少部分地基于那些因素。考虑短语“基于B确定A”。虽然B可能是影响对A的确定的因素,但是这样的短语并不排除对A的确定也基于C。在其它实例中,可以仅仅基于B来确定A。
[0033] 参考图1,图1示出了示出计算系统100的一个实施例的一般化框图。系统100包括处理器102,处理器102包括一个或多个核以及一个或多个级别的高速缓存存储器子系统。系统100还包括存储器控制器120、物理存储器130和位于存储器子系统内的高速缓存110。
物理存储器130可以耦合到存储器层次结构的较低级别,诸如磁盘存储器和离线归档存储器。为了便于说明,这些较低级别的存储器没有被示出。虽然只示出了一个处理器102与相关联的高速缓存110耦合,但是有可能的和被设想的是,系统100可以包括多个处理器和多个相关联的高速缓存,这多个处理器和/或多个相关联的高速缓存耦合到交叉开关(未示出)以将这些组件连接到一个或多个存储器控制器。这一个或多个存储器控制器耦合到物理存储器130。在一个实施例中,物理存储器130包括动态随机存取存储器(DRAM)。DRAM可以包括一个或多个双列直插存储器模块(DIMM)槽。
[0034] 处理器102内的一个或多个核中的每一个核可以包括具有一个或多个多级流水线(pipeline)的超标量微体系架构(superscalar microarchitecture)。此外,每个核可以被设计成执行多个线程。例如,多线程软件应用可以使该软件应用的每个软件线程被调度为在核内的单独流水线上执行,或者可替代地,流水线可以经由某些功能单元处的控制来处理多个线程。
[0035] 在一个实施例中,处理器102内的这些核中的每个核包括用于根据预定义的通用指令集执行指令的电路系统。例如,可以选择 指令集体系架构(ISA)。可替代地,可以选择x86、或任何其它指令集体系架构。通常,处理器102内的这些核中的每个核访问高速缓存存储器子系统内的片上(on-die)一级(L1)高速缓存以获取数据和指令。处理器102可以包括多个片上级别(L2、L3等等)的高速缓存。如果在片上高速缓存或在片外高速缓存110中没有找到所请求的块,那么可以生成对未命中块的读取请求并将该读取请求传输到存储器控制器
120。不同级别的高速缓存之间的接口可以包括任何合适的技术。如高速缓存110中所示,每个级别的高速缓存可以包括用于存储元数据和数据的高速缓存存储器112。此外,每个级别可以包括用于对高速缓存存储器112的访问控制的高速缓存控制器114。
[0036] 在一个实施例中,物理存储器130可以包括纠错码(ECC)DRAM。具有ECC能力的DRAM可以检测和纠正单个位数据错误并且可以检测双位数据错误。存储器错误可以被特征化为软错误或硬错误。软错误可能是短暂的和偶尔的。在节点电容和供电电压两者相对于下几代新处理器随时间而降低的情况下,存储在节点上的电荷量减少。因此,用于存储的节点更容易受到由诸如宇宙射线、阿尔法粒子和中子之类的高能粒子引起的辐射诱导的软错误的影响。这种辐射在晶体管的源极区域和漏极区域处产生将由源极二极管和漏极二极管传送的少数载流子。这种电荷变化与存储在节点上的正随着每一代而减少的总电荷相比可能有足够大的百分比,以至于这种电荷变化超过电路的噪声容限并改变节点的存储状态。虽然电路不会被这种辐射永久损坏,但可能发生逻辑故障。硬错误可能是永久性的,并且可以在硅中或在动态RAM(DRAM)封装的金属化层(metallization)中找到。
[0037] 不管错误的类型如何,错误中的数据位的数量可能改变系统行为。在ECC存储器系统中,单个位的错误通常是可纠正的。由于以上原因,物理存储器130中诸如DRAM的存储器可以使用纠错码(ECC)来检测和纠正软错误。ECC DRAM可以使用称为ECC位的附加位来计算奇偶校验信息。该奇偶校验信息与数据位一起存储在DRAM中。在一个实施例中,存储器控制器120计算奇偶校验信息。当从DRAM读取数据时,存储器控制器120计算新的奇偶校验值,并将该奇偶校验值与所存储的用于正被读取的数据的奇偶校验值进行比较。如果存在失配,那么存储器控制器120可以检测故障位并将其反转。可以在系统管理日志中报告该错误。如果发生多位错误,那么该错误可以被检测并记录但不被纠正。如果系统不能从多位错误中恢复,那么多位错误可能是致命的。
[0038] 备用存储体(spare-bank)存储器和存储器镜像是使得系统能够处置存储器错误(诸如多位错误)的其它高级机制。在一个实施例中,物理存储器130包括备用存储体DRAM。备用存储体存储器特征可以在存储器控制器120和系统基本输入/输出系统(BIOS)软件中实现。这种特征使得管理员能够配置存储器的备用行或存储体以供备用。应当注意的是,虽然本讨论描述了将备用存储器存储体用于版本信息的存储,但是在使用替代的非备用存储体存储的情况下本文描述的方法和机制也是可适用的。例如,版本信息可以简单地存储在存储器内的替代位置中。例如,对应于地址N的版本信息可以存储在诸如N+10000之类的给定的位移处。可替代地,版本信息的位置可以存储在基于与访问地址相关的另一个计算的位置处。在一些实施例中,可以利用专用的影子存储器来存储版本信息。在各个实施例中,版本信息以以下方式存储,即,只需要单次存储器访问就获得所请求的数据和对应的版本信息两者。例如,版本信息可以紧邻所请求的数据来存储,使得在单次访问中获得两者。许多这样的替代方案都是有可能的和被设想的。
[0039] 在一个实施例中,如果在某个时间帧内在任何可用存储体中的特定DIMM上发生的可纠正错误的数量超过在BIOS中设置的给定阈值,那么BIOS指令存储器控制器120将数据从故障的存储体复制到备用存储体。然后存储器控制器120重新映射系统中的存储器。在复制过程完成之后,不再使用故障的存储体。而是使用备用存储体。如所示的,物理存储器130可以被划分成诸如存储器存储体136a-136g的多个逻辑存储体。备用存储体132可以用于在存储体136a-136g中的一个存储体的故障期间替换这个存储体。
[0040] 物理存储器130可以存储以后被编译并加载到高速缓存存储器子系统中的一个或多个软件应用(未示出)。一般而言,对于给定的软件应用,操作系统的内核为该应用设立地址空间、将该应用的代码加载到物理存储器130中、为该应用设立栈、分支到该应用内部的给定位置、并且开始执行该应用。可以在程序执行期间分配用指针访问的动态对象。如所示的,可以在执行一个或多个软件应用期间分配一个或多个字节数组138a-138c。虽然本文通常描述数组,但是所描述的方法和机制也适用于其它类型的数据结构。
[0041] 在一个实施例中,当没有发生DRAM的硬件故障时,所分配的数组138a-138c中的每一个都具有存储在备用存储体132中的版本位134a-134c中的相关联的版本位。可以借用备用存储体132以用于存储要用于存储器损坏检测的版本位的目的。通过读取或写入操作访问所分配的数组138a-138c之一内的存储器位置使得存储在该存储器位置中的数据被返回给处理器102。用于所访问的存储器位置的相关联的版本位可以连同该数据一起被返回给处理器。例如,如果所分配的数组138a内的存储器位置被访问,那么版本位134a可以连同所分配的数组138a内的被访问的数据一起被返回给处理器102。
[0042] 每个存储器访问可以利用由版本位指示的版本号和地址这二者。在一个实施例中,当数据被写入到存储器时,处理器102、高速缓存控制器114或存储器控制器120中的硬件可以验证来自存储操作的版本位与记录在备用存储体132中的相关联的版本位匹配。当数据被加载时,可以发生类似的过程。当发现失配时,可以标志错误。
[0043] 用动态软件监控工具检测也称为陈旧指针的悬空指针是昂贵的,因为仪器会降低系统性能。因此,诸如读取和覆写(overwrite)错误数据以及缓冲器溢出之类的静默存储器损坏是威胁系统可用性和安全性的软件漏洞(bug)的常见来源。可靠的存储器损坏检测对于操作系统(OS)和任何数据库这二者都是重要的。在存储器访问期间通知捕捉处置器何时发生版本位的失配允许OS以很小的开销采取纠正措施。
[0044] 在物理存储器130中的DRAM中的硬件存储器故障的情况下,备用存储体132可以成为活动的并开始存储程序数据。在这种情况下,版本位134a-134c可以不再被存储和用于存储器损坏检测。然而,在这种情况下,系统100可以被很快关闭,DRAM中的一个或多个DIMM可以被更换,并且系统100可以被重新启动。之后,可以再次使用备用存储体132来存储与所分配的数组相关联的版本号。在系统关闭之前,在一个实施例中,对于用于存储器访问的任何相关联的版本号,物理存储器130或存储器控制器120可以向处理器102返回零值。零值可以指示版本号的“未设置”状态。在这种情况下,处理器102、高速缓存控制器114和存储器控制器120中的硬件可以不将应用提供的版本位与由硬件提供的版本位进行比较。在一个实施例中,尽管存储器位置不是通过软件使用的指针本可以访问的存储器位置,应用也可以继续运行。在另一个实施例中,备用存储体132的部分仍然可以在硬件故障期间存储版本位134a-134c中的一个或多个。对于给定版本号返回“未设置”的状态值可以取决于备用存储体132的哪个部分用于硬件故障以及哪个部分仍然用于版本号存储。
[0045] 在各个实施例中,垃圾收集机制可以由计算系统100的各个部分和级别来实现。一种方法是提供垃圾收集机制作为批处理编译器输出的一部分。在这种垃圾收集的方法中,除了为应用支持的功能生成代码之外,批处理编译器还可以生成在没有来自程序员的明确指示的情况下自动回收不可达的存储器空间的代码,并将这种自动回收不可达的存储器空间的代码包括在应用的目标代码中。然而,即使在这种简单的情况下,应用本身并不提供整个垃圾收集器也可能是有意义的。具体而言,应用通常将调用底层操作系统的存储器分配功能。并且操作系统继而可以利用尤其适于在垃圾收集中使用的各种硬件。因此,即使非常简单的系统也可以将垃圾收集机制分散在多个计算机系统层上。
[0046] 在另一个实施例中,当计算系统100采用“虚拟机”时,可以利用另一种垃圾收集方法。在该实施例中,编译器或解释器可以将应用的源代码从高级语言转换为用于虚拟机的被称为“字节码”的指令,其中各种处理器(例如,处理器102)可以被配置为模拟这些虚拟机。编译器和解释器可用于为其产生这种虚拟机指令的高级语言的一个示例是JavaTM编程语言。(Java是Oracle和/或其附属公司的商标或注册商标)。通常,字节码例程由处理器在虚拟机进程的控制下执行,并且虚拟机进程提供包括垃圾收集的存储器管理功能。例如,虚拟机进程的存储器管理组件可以负责根据需要动态分配存储器,并在可能时回收不可达的存储器。可以采用各种其它的垃圾收集方法,包括在硬件中实现垃圾收集功能。
[0047] 虽然实现自动垃圾收集可以极大地减少存储器泄漏和其它软件缺陷的发生,但是如果它没有被小心地实现,那么自动垃圾收集也可能具有显著的不利性能效果。为了将程序中的做“有用的”工作的部分与做垃圾收集的部分区分开来,术语转变器有时用于“有用的”部分;从收集器的观点来看,转变器所做的是转变活动数据结构的连接性。由垃圾收集器执行的指令通常被认为是存储器管理开销,并且已经构想了各种垃圾收集技术(诸如各种类型的增量垃圾收集、分代垃圾收集等)以减少相对于由转变器完成的“有用的”工作的收集开销。通常,分代垃圾收集是指例如基于堆(即,动态分配的存储器)中的对象在多久以前被分配而将这些对象隔离到不同区域(或“代”)中并且单独地管理和收集这些不同的区域或代的技术。分代垃圾收集技术可以依赖于以下一般假设,即,对象的年龄(即,对象最初是在多近的时间被分配)影响对象将保持可达的概率;例如,一些分代垃圾收集器可以被配置为专注于优先收集包含相对较近地分配(“年轻”)的对象的区域,因为假定最近分配的对象比长期存活的对象更快地变得不可达。
[0048] 转变器操作可以以各种方式与垃圾收集操作进行交错(interleave)——例如,垃圾收集器可以周期性地或非周期性地被激活以执行所谓的垃圾收集“循环”或“周期”,在此期间,可以为了不可达对象而检查用于转变器的堆的一部分或全部,并且可以回收找到的不可达对象。在周期完成之后,可以停用垃圾收集器,直到例如通过检测到没有充足的堆存储器保持空闲或者基于调度而触发下一个周期。在一些实现中,转变器可以与垃圾收集周期同时地继续该转变器的操作,而在其它实现中,可以在垃圾收集周期的至少一部分期间挂起(suspend)转变器操作。其中转变器在垃圾收集期间被挂起的垃圾收集方案可以被称为“停止世界(stop the world)”方案或算法。这样的方案要求转变器在整个垃圾收集周期期间保持被挂起。
[0049] 许多现代的转变器应用可以具有大量的存活(即,可达的)堆数据和相当大的线程级并行性的特点,并且可以在计算系统100上运行以实现期望的性能目标。在当今和将来的服务器中的堆越来越大的情况下,这些停止世界算法是不可扩展的,这导致高并且不可预测的暂停时间。相应地,在一个实施例中,硬件辅助的垃圾收集算法可以由计算系统100执行以将存活对象从一个或多个存储器区域移动到另一个“清洁”区域。当对象正在被迁移时,这些对象可以以紧凑的格式存储在新的“清洁”区域中以使存储器碎片最少。在一个实施例中,垃圾收集算法可以完全绕过OS,因为存活集合标记可以使用JVM级加载/存储指令来标记每个存储器区域的即将被迁移的存活集合。垃圾收集算法可以启用与应用堆大小相一致的并发和连续的细粒度对象迁移,使得Java应用线程(或转变器)可以在对象正被迁移的同时取得进展。
[0050] 在各个实施例中,存储器版本指令和技术可以与垃圾收集结合使用。这样的技术可以被称为存储器损坏检测(MCD)或应用数据完整性(ADI)。在各个实施例中,软件开发者可以使用这样的指令和机制来执行各种功能,这些功能至少包括初始化堆、每线程的检查控制、以及存储器标记。例如,可以初始化JVM,使得在对象被管理(分配)的堆区域上启用存储器版本控制。可以使用OS系统调用来通知OS关于哪个VA空间应当被管理为MCD区域。此外,可以为每个转变器线程启用MCD检查。此外,可以使用各种指令和机制来控制哪些硬件线程正在对加载和存储执行MCD检查。在各个实施例中,可以存在用于每个运行线程的硬件(HW)控制寄存器(例如,由OS/管理程序(HV)管理)。还有,即将把存活对象的集合从一个存储器区域迁移到另一个存储器区域的垃圾收集(GC)线程可以发出具有特殊/保留的MCD值的存储,使得转变器可以在堆的该“标记用于迁移的存活集合”的区域上进行捕捉。MCD定义只存储存储器版本并使应用数据保持不变的特殊存储“风格(flavor)”。当堆区域被定义为“MCD区域”时,开发人员可以用MCD存储指令翻转存储器版本信息,以避免任何OS/HV API开销。
[0051] 如前所述,垃圾收集算法经常将存活对象从一个或多个存储器区域移动(或“迁移”)到另一个区域。除了这种对象迁移之外,被移动的对象还可以被合并,以便以更紧凑的格式存储它们。以这种方式,可以减少存储器碎片。利用“停止世界”方案的垃圾收集器使得应用线程(例如,JAVA转变器)在对象被迁移时完全暂停。在当今和将来的服务器中的堆越来越大的情况下,这些停止世界算法是不可扩展的,这导致高并且不可预测的暂停时间。
[0052] 本文所描述的方法和机制启用与应用堆大小相一致的并发和连续的对象迁移。在各个实施例中,操作系统可以被完全绕开,因为存活集合标记可以使用应用/JVM级加载/存储指令来标记每个存储器区域的即将被迁移的存活集合(例如,作为垃圾收集或某种其它对象迁移过程的一部分)。
[0053] 在一个实施例中,单个存储器版本值可以被保留并被用于将被考虑用于迁移的对象标记为“已迁移或即将迁移”。在其它实施例中,可以使用更多值来细化算法并潜在地获得更好的性能。因此,算法启用连续和并发的操作,使得进程和线程(例如,Java应用线程)可以在对象正被迁移的同时取得进展。
[0054] 此外,垃圾收集标记可以在巨大的存储器页面内完成。这允许终端用户使用大页面并且具有较低的性能代偿。由于大存储器页面不能在应用中使用,因此以前的解决方案包括可能放开安全性问题和/或付出性能成本的重大的OS修改,终端用户已经习惯了这样。
[0055] 如所提及的,区域垃圾收集算法将大堆划分成一组较小的存储器区域。垃圾收集线程并发和连续地跟踪应用的存活集合(即,当前正在使用的对象),并且在每个区域的撤离(evacuation)可以被执行之前,每个区域的存活集合是已知的并且存储在简单的数组结构中。取决于机器的大小(线程+堆),可以确定最佳区域大小,使得存储器迁移可以在预先配置的时间边界(例如1-10毫秒)内执行。
[0056] 在一个实施例中,区域标记可以使用存储器版本控制技术,这可以是硬件辅助的。即将对区域进行迁移的垃圾收集线程可以基于存活集合数组内容用指令(例如,MCD存储指令)执行标记。一般而言,这可以是刚好在一个或多个存储器区域上发生存储器重定位之前的阶段。传统上,所有的线程都将在该阶段被停止,并且GC线程将把东西四处移动并修补存活的引用。作为对照,在一个实施例中,线程可以停止非常微小的时间段,并且通过将存储器版本从未版本化(例如,0x0)翻转到当前堆区域中的每个存活对象的保留/特殊值(例如,
0xa)来准备重定位。
[0057] 例如,假定给定区域大小为128MB。GC线程已经识别存活集合,并且在这128MB区域上例如可能有5个存活对象。每个对象位于该区域中的不同VA位置处,这些对象具有以下大小:16字节、42字节、48字节、256字节和400字节。在各个实施例中,MCD版本以64B粒度存储在存储器中。因此,GC线程将需要以以下方式通过MCD存储来覆盖每个对象的VA空间:(1)检查每个对象的对齐,以及(2)如果对象小于64B并且它不跨越64B对齐边界,那么发出具有特殊/保留值的一个MCD存储。
[0058] 在以上的示例中,可以假设16字节对象和42字节对象各自被很好地存储在一个64B高速缓存行中,使得可以只使用一个MCD存储来翻转存储器版本。如果48字节对象恰好跨越高速缓存行边界,那么可以使用两个MCD存储来覆盖整个对象——一个字节的存储位于这48个字节的开始处,并且接触(touch)跨越字节的另一个存储位于接下来的高速缓存行中。为了说明的目的,可以假设256字节对象恰好很好地对齐,使得4个MCD存储可以覆盖所有底层的高速缓存行,等等……当该128MB区域中的整个存活集合被标记时,GC可以开始迁移阶段,在一个实施例中,该迁移阶段可以涉及传统的GC迁移操作。
[0059] 存活对象的每个高速缓存行将获得新的存储器版本,使得任何接下来的加载可以触发用户级捕捉例程来解决依赖性。如果在迁移仍在发生时(例如,转变器加载),转变器线程恰好接触这些对象之一(例如256字节对象),那么将导致MCD捕捉,因为该加载正在期望/使用存储器版本零(在指针中被编码),而存储器包含最近被进行迁移的GC线程翻转了的不同版本(例如,版本0xa)。因此,当此捕捉发生时,存在几个选择:1)等待,直到所有5个对象的迁移都完成,2)等待,直到256字节的迁移完成。当对象被迁移时,本地GC数据结构将具有足够的信息将转变器指向该对象的新位置。捕捉处置器可以遵循该新引用,并且包含该对象的新VA的加载可以被重新执行。当整个存活集合被标记时,所有的应用线程都被允许保持运行。在区域迁移时间期间可以有可触发用户级捕捉的小段时间,因为应用(转变器)线程之一正在接触来自当前区域中的正被迁移的存活集合对象之一。用户级捕捉处置器可以通过指针修补和从另一个虚拟地址(VA)位置重新执行来解决该冲突,使得暂停时间被保持在预定的限制内。在一些实施例中,当版本翻转(如上所述)正在发生时,更保守的算法可以在很短的时间段内停止所有转变器。在这种情况下,确保了在MCD“存储器版本喷涂(spraying)”操作期间没有加载正在发生。
[0060] 当所有对象都从一个区域迁移时,它们可以以紧凑形式放置在另一个位置中,并且所有存储器版本可以被恢复为“正常”。多个区域可以被并行地迁移以跟上应用存储器压力。
[0061] 现在参考图2,图2示出了示出进程地址空间的一个实施例的一般化框图。如上所述,用于给定进程的地址空间可以是连续的虚拟地址空间,其中虚拟地址和物理地址之间的映射确定数据值和应用代码在物理存储器130中的位置。编译器和高级语言的交互影响软件应用如何使用指令集体系架构(ISA)。软件应用开发使用要被分配和寻址的若干变量,以及用于分配变量的若干寄存器。在一个实施例中,静态数据220、栈250和堆230确定用于应用代码210的数据分配。
[0062] 静态数据220可以用于分配诸如全局变量和常量之类的静态声明的对象。这些对象中的大多数可以是数组。栈250可以用于分配标量变量而不是数组,诸如当前正被调取的函数中的局部变量和参数。栈250可以分别在过程调用或返回时增长和收缩。堆230可以用于分配用指针访问的动态对象,并且这些动态对象通常不是标量变量。堆230可以用于通过在串/列表操作期间存储临时串或列表的内容来减少复制串和列表的内容的频率。堆230不受函数调用的返回的影响。
[0063] 现在转到图3,图3示出了示出存储器访问地址格式的一个实施例的一般化框图。现代计算系统使用虚拟存储器,以便在许多进程之间共享较少量的物理存储器。地址空间可以是连续的虚拟地址空间,其中虚拟地址和物理地址之间的映射确定存储的数据在物理存储器中的位置。
[0064] 当软件用诸如用于动态存储器分配的calloc或malloc C++子例程来分配存储器的区域时,版本号可以被指派给所分配的数组。子例程和/或堆管理器可以在迭代循环内利用修改后的块初始化存储指令使所分配的数组归零。这种修改后的指令可以基于高速缓存行来操作。例如,可以使用128个修改后的块存储指令来分配8千字节(KB)数组,其中每个高速缓存行是64字节。此外,修改后的块存储指令可以使得相关联的版本号存储在图1中所示的备用存储体132中。
[0065] 在一个实施例中,通过状态位(诸如存储器损坏检测(mcd)状态位)使得OS知道额外的元数据正被用于存储器访问操作。在一个实施例中,当mcd状态位被解除断言(deasserted)时,虚拟地址位330的最高有效位(MSb)被符号扩展以提供经符号扩展的位320。在一个实施例中,如果位320不等于虚拟地址位330的MSb的经符号扩展的值,那么可能发生异常。
[0066] 在一个实施例中,当mcd状态位被断言时,虚拟地址位330的MSb对于全部地址的较小一部分进行符号扩展。在这种情况下,经符号扩展的值320较小。在一个实施例中,存储器访问地址的较高位存储用于以后的比较的相关联的版本号310。在一个实施例中,存储器访问地址是64位值。虚拟地址330包括位53至位0。当mcd状态位被断言时,经符号扩展的值320包括位59至位54,并且版本号310包括位63至位60。在其它实施例中,版本号310可以利用除4之外的其它数量的位,并且其它地址可以具有其它数量的位。虽然存储器访问地址中的位以这种特定顺序示出,但是其它组合也是可能的,并且也可以利用其它的或附加的位。存储用于部分310-330的信息的位可以是连续的或者可以不是连续的。类似地,为了更好的设计权衡,部分310-330的布置可以使用其它放置方式。
[0067] 现在转到图4,图4示出了示出用于版本号失配的真值表的一个实施例的一般化框图。在一个实施例中,可以使用的版本号的可能值在可用集合或保留集合中。保留集合中的版本号可以指示存储器未利用版本号或存储器不能利用版本号。例如,当在DRAM中发生硬件故障并且故障转移机制开始使用备用存储体132时,存储的版本号可能不再被使用。在另一个示例中,发生了不可纠正的错误,并且存储器没有返回有效数据。
[0068] 在一个实施例中,用于保留集合一个值可以足以处置上述状况。然而,可以在保留集合中使用另一个版本号值,以便于软件采用mcd状态。例如,如图2中所示,堆230可以占用虚拟地址空间的下一半。在这种情况下,相关联的虚拟地址的最高有效位可以包括二进制0。栈250和共享库可以占用虚拟地址空间的上一半。相关联的虚拟地址的最高有效位可以包括二进制1。保留集合中的单个版本号值可能使软件(诸如OS)难以确定指向虚拟地址空间的上一半的指针是否在可用集合中具有相关联的版本号。例如,对于4-位版本号0xF(其中0x表示十六进制值),该值可以指示相关联的存储器访问地址与具有等于0xF的版本号的存储器位置对应,或者存储器访问地址与没有被指派版本号的存储器位置对应。为了简化逻辑,可以将0x0值和0xF值两者放置在保留集合中。对于4-位版本号示例,0x0和0xF之间的其它值可以被放置在可用集合中。
[0069] 软件可以使用可用集合中的版本号值以用于将版本号指派给所分配的数组138a-138c。值“A”和值“B”表示可用集合的两个不同成员,但是值A和值B彼此不相等。在一个示例中,当版本号包括4位时,保留集合可以包括2个值0x0和0xF,并且可用集合可以包括14个值即0x1到0xE。
[0070] 如真值表中所示,当与来自处理器102的加载或存储操作对应的存储器访问地址中的版本号在可用集合中,但是该版本号与存储在备用存储体132中的与由存储器访问地址识别出的存储器位置相关联的版本号不匹配时,可能发生版本失配。此外,存储在备用存储体132中的版本号在可用集合中以使失配发生。如表中所示,当存储在备用存储体132中的版本号在保留集合内时,不发生失配。当与来自处理器102的加载或存储操作对应的存储器访问地址中的版本号在保留集合中时,发生了意外状况。相应地,该意外的发生导致检测到失配。
[0071] 现在参考图5,图5示出了示出存储器接口的一个实施例的一般化框图,该存储器接口示出存储器请求的不同来源。应当注意的是,图5中所示的组件示出组件的一般组织和耦合,而不是这些组件的实际物理放置方式。在一个实施例中,高速缓存550包括高速缓存存储器552、高速缓存控制器554和未命中缓冲器556。高速缓存550可以对应于具有伴随的未命中缓冲器556的核上(on-core)L2高速缓存。
[0072] 高速缓存存储器550可以大于层次结构中先前级别的存储器,先前级别的存储器诸如处理器102中的L1高速缓存。高速缓存存储器550可以包含先前级别的所有高速缓存行。在一个实施例中,为了从L1高速缓存中移除复杂性,L1高速缓存被实现为直写高速缓存并且L2高速缓存管理存储器排序和一致性问题。因此,处理器102内的存储器请求可以被发送到L1高速缓存和诸如高速缓存550的L2高速缓存两者。
[0073] 存储器请求至少可以源自指令取回单元(IFU)510、加载-存储单元(LSU)520内的加载缓冲器522和存储队列526。IFU 510可以被配置为选择要被取回的线程和为所选择的线程从指令高速缓存(i-cache)中取回指令,该指令高速缓存可以对应于具有对应的L2高速缓存550的L1高速缓存。解码器(未示出)可以耦合到IFU 510以确定每个取回的指令的指令类型。处理器102内的多级流水线中的执行单元(未示出)可以生成用于存储器访问操作的地址。该地址可以至少包括用于对应于该存储器访问操作的数组的相关联的版本号。存储队列526可以被配置为为所选择的线程将存储器请求传送到相同的L1高速缓存和L2高速缓存,以便为所选择的线程写出提交的存储指令的数据。加载缓冲器522可以被配置为为所选择的线程将存储器请求传送到相同的L1高速缓存和L2高速缓存,以便读取正被执行的加载指令的数据。
[0074] 在一个实施例中,未命中缓冲器556包括多个条目,这些条目将所有遇到阻止操作完成的状况的读取和写入操作(诸如加载、取回和存储指令)排队。例如,所请求的高速缓存行可能不存在于高速缓存存储器552中。可替代地,所请求的高速缓存行可能存在于高速缓存存储器中,但是它不具有特定的高速缓存一致性状态。例如,高速缓存存储器552可以被选择为存储器模型的全局排序点(global ordering point)。为了遵守存储器模型的规则,可能需要在存储器层次结构内有用作所有存储操作的参考的全局排序点,该全局排序点诸如可以是具有相关联的直写L1高速缓存的L2高速缓存的高速缓存存储器552。这种全局排序点可以负责确保所有消费者都将看到存储操作的一致和正确的排序。这通常通过要求在执行存储操作之前高速缓存行处于独占状态来实现。如果高速缓存行不处于独占状态,那么发生高速缓存未命中,并且可能需要获得更新后的对应的高速缓存行。
[0075] 在一个实施例中,存储队列(SQ)526保持处理器102中所有线程的所有提交的存储指令或操作。当存储指令提交时,该指令通常从存储缓冲器524移动到存储队列526。在一个实施例中,存储缓冲器524和存储队列526存储相同的字段530-544。然而,当存储指令提交时,版本号538、mcd启用状态540和其它上下文信息542可以不再与地址536相关联。相反,这些信息可以与数据544相关联。如果处理器102被配置为将指令划分成两个或更多个操作,那么缓冲的存储操作也可以是微操作或者微指令(micro-ops)。
[0076] 存储队列526可以用于写后读(RAW)危险(hazard)检查,因为所有加载指令或操作可以在被发出之前针对RAW危险检查存储队列526。数据544保持提交的存储指令的数据,直到这些指令向高速缓存550写出数据并且存储指令的对应数据现在对于计算系统内的所有处理器和线程是全局可见的。对于特定的加载指令,当在存储队列526中对于具有有效数据的特定条目检测到RAW危险时,可以立即发生绕开。
[0077] 存储队列526包括多个条目,其中每个条目对应于存储指令。在一个实施例中,每个条目包括条目号530、状态信息532、线程标识(TID)号534、地址536、版本号538、存储器损坏检测启用状态540以及其它上下文识别信息542。其它上下文信息542可以包括基于线程的mcd启用检查状态信息。虽然这些字段是以这种特定顺序示出的,但是其它组合也是可能的,并且可以利用附加字段。为字段530-542存储信息的位可以是连续的或者可以不是连续的。类似地,为了更好的设计权衡,字段530-542的布置可以使用其它放置方式。条目号530对应于该条目在存储队列526中的位置,其中条目0可以被配置为在存储队列526的顶部或底部,这取决于逻辑偏好。条目字段530可以是隐含的而不是实际存储的数字。对应于处理器核102内的核流水线中的单个存储指令的资源标签或存储队列标签也可以在存储队列526中按条目地进行保持。
[0078] 状态信息532可以包括与存储在存储缓冲器524中的对应数据相关联的高速缓存行MESI协议信息和一个或多个有效位。线程标识符(TID)534可以用于识别用于特定存储操作的对应线程。在一个实施例中,地址字段536可以保持物理地址和字节掩码。条目可以在存储指令退出时写入。加载指令可以发起通常经由动态电路逻辑实现的内容可寻址存储器(CAM)比较操作,以便检查地址重叠。在一个实施例中,当地址536匹配、线程ID 534匹配并且加载掩码中的任何位在存储掩码中具有匹配时,发生地址重叠。对于具有地址重叠的条目,CAM还将检查完全匹配或部分匹配。当加载掩码中的每个位在存储掩码中具有对应的位时,发生完全匹配。否则,匹配是部分的。版本号538、mcd启用状态540和其它上下文信息542可以不参与存储缓冲器524内的典型CAM操作。
[0079] 现在参考图6,图6示出了示出用于初始化具有版本号的数组的方法的一个实施例的一般化流程图。上述系统100中体现的组件可以根据方法一般地进行操作。为了讨论的目的,本实施例中的步骤以序列的顺序示出。然而,一些步骤可以以与所示不同的顺序发生,一些步骤可以并发地执行,一些步骤可以与其它步骤组合,并且在另一个实施例中,一些步骤可以不存在。
[0080] 在块602中,处理器102可以正在执行对应于一个或多个软件应用的一个或多个线程的指令。处理器102可以并发地取回用于一个或多个线程的指令。这些取回的指令被解码。如前所述,用指针访问的动态对象可以在程序执行期间被分配。在一个实施例中,C和C++编程语言中使用的calloc子例程或malloc子例程被调用以用于存储器的动态分配。
[0081] 如果在执行期间检测到要分配的字节数组(条件块604),那么在块606中,为该数组确定版本号。如前所述,版本号可以属于诸如保留集合和可用集合的两个类别中的一个。在一个实施例中,可以选择可用版本号集合内的尚未被指派的值。在一个实施例中,OS确定保留集合和可用集合中的每一个集合内的值,并且选择用于要分配的数组的版本号。当OS从处理器102接收到动态存储器分配子例程正在被执行的指示时,OS可以执行该确定和选择。在另一个实施例中,处理器102确定保留集合和可用集合中的每一个集合内的值,并且选择用于要分配的数组的版本号。处理器可以将所选择的版本号与正在执行动态存储器分配子例程的伴随指示发送到OS。
[0082] 在块608中,用修改后的块初始化存储指令执行用于动态存储器分配的子例程。该子例程可以在迭代循环中使用此指令。例如,128个循环迭代(每个循环迭代具有修改后的块存储指令)可以用于分配8千字节(KB)数组,其中由单次迭代分配的每个高速缓存行是64字节。该修改后的块初始化指令可以将零存储到由变量地址指向的整个高速缓存行。在一个实施例中,版本号可以被记录在该地址的高位中。
[0083] 在块610中,在执行期间,修改后的指令可以提取这些高位,并将这些位放置在备用存储体132中的存储器位置中,备用存储体132中的该存储器位置与由地址的剩余位识别出的存储器存储体136a-136g之一中的存储器位置相关联。可以贯穿整个存储器系统连同相关联的高速缓存行一起携带该版本号。
[0084] 当calloc、malloc或类似的子例程完成时,在块612中,子例程返回指针值和物理存储器的范围,其识别虚拟存储器中所分配和初始化的数组。在一个实施例中,寄存器的较低部分(诸如较低的54位)可以用于识别虚拟存储器内的位置。子例程可以返回指针值,该指针值具有保持版本号的最高有效位。例如,64位虚拟地址可以在位63至位60中保持4-位版本号。可以用用于所分配的数组的物理存储器的范围和该指针值来执行使用加载和存储指令的对虚拟存储器的引用。设置指针中的位以保持版本号可以使用逻辑运算来执行。设置物理存储器130中的备用存储体132中的位可以通过将该版本号值存储在备用存储体132中的与所分配的数组对应的每个存储位置中来执行。
[0085] 现在参考图7,图7示出了示出用于执行具有版本号的存储器访问操作的方法的一个实施例的一般化框图。上述系统100中体现的组件可以根据方法一般地进行操作。为了讨论的目的,本实施例中的步骤以序列的顺序示出。然而,一些步骤可以以与所示不同的顺序发生,一些步骤可以并发地执行,一些步骤可以与其它步骤组合,并且在另一个实施例中,一些步骤可以不存在。
[0086] 类似于图6的方法中的块602,在块702中,处理器102可以正在执行对应于一个或多个软件应用的一个或多个线程的指令。如果在执行期间检测到诸如加载或存储指令之类的存储器访问操作(条件块704),那么在块706中,识别用于该操作的相关联的数组。在图6的方法中的步骤612中返回的相关联的指针值可以在步骤706中另外识别。
[0087] 在块708中,识别与数组相关联的第一版本号。例如,如上所述,该第一版本号可以存储在指针值的高位中。在块710中,识别第二版本号,其中第二版本号与由存储器访问操作的地址指示的存储器位置相关联。例如,可以在块706中识别数组,并且在块708中识别相关联的指针值。该数组可以保持100个高速缓存行的信息。所识别的指针值和100个高速缓存行的大小两者都可以用于生成特定的地址。这些特定的地址可以对应于计算机程序中的迭代循环内的存储器访问操作。例如,指针值可以识别数组开始处的高速缓存行,诸如Start+0。作为简单的说明,数组末尾处的高速缓存行可以由通用地址Start+99来识别。然而,存储器损坏会导致使用不正确的地址并且可能在循环的迭代期间访问由Start+100识别出的高速缓存行。
[0088] 在一个实施例中,存储器损坏错误报告条件可以包括断言的mcd状态和存储在存储器中的第二版本号不是保留集合中的值的确定。如果该错误报告条件为假(条件块712),那么在块714中,存储器访问操作继续执行到完成。如果该错误报告条件为真(条件块712),那么在块716中,第一版本号被与第二版本号进行比较。
[0089] 在一个实施例中,当存储指令提交、到达存储队列的头部并且由直写机制发送到L2高速缓存时,为该存储指令执行以上比较。第一版本号被存储在存储地址中。第二个版本号被存储在L2高速缓存中。相关联的L2高速缓存控制器可以执行第一版本号和第二版本号的比较。对于加载指令,处理器102内的核可以将具有第一版本号的加载地址发送到L1高速缓存。从L1高速缓存返回的高速缓存行可以存储第二版本号。处理器102内的核可以比较第一版本号和第二版本号。在一个实施例中,直到正在执行的计算机程序实际请求预先取回的高速缓存行才为这些预先取回的行执行比较。
[0090] 如果以上比较找到匹配(条件块718),那么该方法的控制流程移动到块714,其中存储器访问操作继续到完成。如果以上比较找到失配(条件块718),那么在块720中,设置错误标志或捕捉。
[0091] 在一个实施例中,处理器102的核内的捕捉逻辑单元(TLU)可以被配置为接收在特定线程的执行期间发生的异常事件(诸如在以上比较期间发现的失配)的通知。对于加载指令,失配可以由处理器102内的对应于加载缓冲器的电路系统找到并报告。对于存储指令,失配可以如上所述由与L2高速缓存相关联的高速缓存控制器找到并报告。缓存控制器可以向处理器102内的核发送对应于所找到的失配的指示。加载-存储单元(LSU)520可以存储识别提交并离开存储队列526的给定存储操作的信息,以防该给定存储操作以后导致捕捉。该识别信息可以用于以后的调试过程。
[0092] TLU可以使得对该线程的执行控制引导到(vector to)与检测到的事件对应的监督模式软件处置器(即,捕捉处置器)。在一个实施例中,TLU可以被配置为将来自捕捉线程的所有指令从处理器102内的相关联的核内的任何处理阶段清除,而不中断其它非捕捉线程的执行。
[0093] 现在转到图8,图8示出了示出用于执行更新版本号的存储器访问操作的方法的一个实施例的一般化流程图。上述系统100中体现的组件可以根据方法一般地进行操作。为了讨论的目的,本实施例中的步骤以序列的顺序示出。然而,一些步骤可以以与所示不同的顺序发生,一些步骤可以并发地执行,一些步骤可以与其它步骤组合,并且在另一个实施例中,一些步骤可以不存在。
[0094] 在块802中,处理器可以正在执行软件应用的指令。在存储器行中,指令可以被单独地取回或与其它指令组合地取回。如果所取回的指令(诸如存储器访问指令)的操作码对应于版本号访问(条件块804),那么接下来可以确定指令的类型。如果所取回的指令的操作码不是存储指令(条件块808),那么在块814中,解码器可以确定所取回的存储器访问指令是否是加载指令。如果所取回的存储器访问指令是加载指令,那么该方法可以用于执行该加载指令,这将在下面进一步描述。如果所取回的存储器访问指令不是加载指令,那么可以标志异常,因为存储器访问指令只可以读取或写入存储器中的位置。
[0095] 如果所取回的存储器访问指令的操作码是存储指令(条件块808),那么在块810中,当存储数据可用时,该存储数据被写入到由存储地址识别出的物理存储器中的位置。如果指令是块初始化存储指令,那么存储数据可以是用于初始化新分配的数组中的高速缓存行的零。否则,存储数据可以对应于提交的存储指令的数据。
[0096] 如果所取回的存储指令不对应于版本更新访问(条件块812),那么在块814中,存储地址和物理存储器中的版本号可以被比较。该步骤相当于方法中的块716和后续的块。如果所取回的存储指令对应于版本更新访问(条件块812),那么在块816中,可以用存储地址内的版本号覆写由存储地址识别出的位置中的版本号。这种类型的存储指令可以用于将物理存储器的第一区域复制到物理存储器的第二区域。此外,这种类型的存储指令可以用于将存储器的给定区域从盘中带到物理存储器。在这种类型的存储指令的执行期间,可以不执行版本号的比较。
[0097] 现在转到图9,图9示出了用于执行更新版本号的存储器访问操作的方法的另一个实施例。上述系统100中体现的组件可以根据方法一般地进行操作。为了讨论的目的,本实施例中的步骤以序列的顺序示出。然而,一些步骤可以以与所示不同的顺序发生,一些步骤可以并发地执行,一些步骤可以与其它步骤组合,并且在另一个实施例中,一些步骤可以不存在。
[0098] 在块902中,所取回的指令被确定为对应于版本号访问的加载指令。该步骤可以对应于图8的方法中的块814。在块904中,处理器从由加载地址识别出的物理存储器中的位置读取版本号。如果用于所取回的加载指令的操作码对应于版本更新(条件块906),那么在块912中,当所读取的版本号被存储在目的地寄存器中时,该指令的执行完成。该加载指令可以用于读取版本号以用于以后存储到物理存储器中的不同位置,诸如用于复制操作。
[0099] 如果用于所取回的加载指令的操作码不对应于版本更新(条件块906),那么在块908中,在由加载地址识别出的物理存储器中的位置中的数据被读入到目的地寄存器中。在块910中,加载地址和物理存储器中的版本号可以被比较。该步骤相当于图7的方法中的块
716和后续的块。
[0100] 现在转到图10,图10示出了用于执行硬件辅助的细粒度对象存储器迁移的方法1000的一个实施例。上述系统100中体现的组件(例如,处理器102)可以根据方法1000一般地进行操作。此外,本实施例中的步骤以序列的顺序示出。然而,一些步骤可以以与所示不同的顺序发生,一些步骤可以并发地执行,一些步骤可以与其它步骤组合,并且在另一个实施例中,一些步骤可以不存在。
[0101] 处理器可以准备将存活对象从堆的第一区域迁移到堆的第二区域(块1005)。处理器可以存储跟踪堆(或堆的各个区域)内的存活对象集合的存活集合数组,并且该存活集合数组可以用于识别堆的第一区域的存活对象。在一个实施例中,处理器可以执行多个垃圾收集线程用于执行对象迁移。接下来,处理器可以检测第一区域内的第一存活对象(块1010)。
[0102] 然后,处理器可以标记第一对象用于从第一区域迁移到第二区域(块1015)。在一个实施例中,标记第一对象用于迁移可能需要执行MCD存储指令以将第一对象的存储器版本号从第一版本号翻转到第二版本号。该MCD存储指令可以只存储存储器版本,并且可以使应用数据保持不变。在一个实施例中,第一对象的存储器版本号可以被改变为为对象迁移保留的值。
[0103] 接下来,在第一对象被迁移到第二区域之前,处理器可以检测对第一对象的访问(块1020)。在一个实施例中,处理器可以被配置为在转变器线程访问第一对象时检测在转变器线程和第一对象之间何时存在存储器版本号失配。响应于检测到该访问,处理器可以停止对第一对象的访问(块1025)。然后,处理器可以触发捕捉例程来进一步解决依赖性(块1030)。在一个实施例中,用户级捕捉例程可以通过指针修补和从另一个虚拟地址(VA)位置重新执行来解决访问的冲突,使得暂停时间被保持在预定限制内。最终,处理器可以将第一对象从第一区域移动到第二区域(块1035)。在第一对象已被迁移到第二区域后,处理器可以清除第一对象的标记(块1040)。在一个实施例中,清除第一对象的标记可能需要将第一对象的存储器版本号从第二版本号翻转回第一版本号。在块1040之后,方法1000可以结束。
[0104] 现在参考图11,图11示出了用于将对象从一个存储器位置迁移到另一个存储器位置的方法1100的一个实施例。上述计算系统100中体现的组件(例如,处理器102)可以根据方法1100一般地进行操作。此外,本实施例中的步骤以序列的顺序示出。然而,一些步骤可以以与所示不同的顺序发生,一些步骤可以并发地执行,一些步骤可以与其它步骤组合,并且在另一个实施例中,一些步骤可以不存在。
[0105] 处理器可以执行一个或多个垃圾收集(GC)线程以开始存储器区域的迁移(块1105)。处理器可以用MCD版本来标记存储器区域的存活集合(块1110)。在一个实施例中,迁移标记阶段可以在所有转变器线程都暂停的所谓的安全点下发生。这将消除在存活集合标记正在发生时与转变器线程的冲突。在一个实施例中,GC线程可以通过执行位向量遍历来标记存储器区域内的所有存活对象。在本实施例中,存活集合位向量中的每个位可以表示堆虚拟地址(VA)空间的8个字节、16个字节或另一数量的数据。如果该位被设置,那么GC线程将在匹配的VA空间位置上存储MCD版本。处理器可以重复标记,直到存储器区域的存活集合的所有虚拟地址(VA)空间都用MCD存储指令标记(块1115)。在用新的存储器版本标记存活集合之后,处理器可以释放所有转变器(块1120)。然后,处理器可以将每个对象迁移到另一个存储器位置并且原子地更新本地数据结构,使得任何相关的存储器访问可以指向该新的位置(在捕捉处置器内部)(块1125)。如果GC线程没有完成迁移,那么捕捉处置器可以具有迁移给定对象的选项。换句话说,转变器线程将在短时间内成为GC线程。接下来,迁移后的对象的所有存储器版本可以被清除回到“常规的”非捕捉版本号(例如,0x0)(块1130)。在块1130之后,方法1100可以结束。
[0106] 现在参考图12,图12示出了用于迁移存活对象的方法1200的一个实施例。上述计算系统100中体现的组件(例如,处理器102)可以根据方法1200一般地进行操作。此外,本实施例中的步骤以序列的顺序示出。然而,一些步骤可以以与所示不同的顺序发生,一些步骤可以并发地执行,一些步骤可以与其它步骤组合,并且在另一个实施例中,一些步骤可以不存在。
[0107] 处理器可以发起将一个或多个对象中的对象从第一存储器位置迁移到第二存储器位置的过程,该对象具有相关联的第一版本号(块1205)。接下来,处理器可以存储将该对象与不同于第一版本号的第二版本号相关联的指示(块1210)。然后,处理器可以检测对包括第一版本号的对象的访问(块1215)。响应于检测到对包括第一版本号的对象的访问,处理器可以暂时停止该访问(块1220)。在一个实施例中,处理器还可以响应于检测到对包括第一版本号的对象的访问而触发用户级捕捉例程以进一步解决依赖性。
[0108] 接下来,处理器可以将该对象从第一存储器位置移动到第二存储器位置(块1225)。然后,处理器可以存储将该对象与第一版本号相关联的指示(块1230)。在块1230之后,方法1200可以结束。
[0109] 应当注意的是,上述实施例可以包括软件。在这样的实施例中,实现方法和/或机制的程序指令可以被传送或存储在计算机可读介质上。配置为存储程序指令的许多类型的介质都是可用的,并且包括硬盘、软盘、CD-ROM、DVD、闪存存储器、可编程ROM(PROM)、随机存取存储器(RAM)以及各种其它形式的易失性或非易失性存储装置。
[0110] 虽然已经相当详细地描述了以上实施例,但是一旦以上公开被完全理解,许多变化和修改对于本领域技术人员将是明显的。以下权利要求旨在被解释为涵盖所有这样的变化和修改。