动态编译器

连接两种体系结构的编译器

动态编译器是连接两种体系结构的编译器,让其中一个体系结构上的二进制代码经过翻译以后运行在另一个体系结构上。其中被翻译的那个体系结构成为源体系结构,在这个体系结构上编译的程序是动态编译器的输入;而在底层实际运行,使得二进制代码能够正确运行的体系结构,称之为目标体系结构。

简介
传统的编译器,即静态编译器,把一个程序的源代码编译为机器可识别的目标代码(即可执行文件)。尽管静态编译器十分普遍,由于它往往只能在一种体系结构上运行,所以限制很大。从理论上来看,我们可以把针对某个体系结构的二进制代码通过反编译转换成源代码,再通过另一个编译器转换成我们想要的那个体系结构上的可执行文件。然而,由于编译器之间的差异很大,加上反编译的正确性和性能并不让人满意,所以最后导致了动态编译器的诞生。
最初的动态编译器来自于解释器,通过解释器对源代码的解释,来执行和解释器同一平台上的程序。可是,这样的执行效率低下,用户难以忍受。为了解决这一问题,人们发明了编译-解释器。编译-解释器先把源代码编译成字节码(bytecode),也就是编译前端的输出文件,然后等到执行的时候,通过解释字节码执行程序。这种方式存在了很多年,但是近年来随着人们对程序性能要求的不断提高,编译-解释器的性能也不能满足目前的需要了
20 世纪80 年代初,Smalltalk 的实现首次探索了真正的动态编译,随后Java 虚拟机的出现推进了JIT(Just-In-Time)的技术进步。起初,动态编译器的性能并不理想,后来,随着字节码长度的缩短和编译方式的简化,动态编译器的性能越来越高,针对体系结构的优化也逐步引入,这大大提高了动态编译器的竞争力。
1997 年前后,Sun 公司推出的HotSpot 编译器是第一款高性能的Java 动态编译器。随着Java 技术的普及和计算机体系结构的改良,动态编译器的应用领域也越来越广。目前动态编译技术已经应用于所有常用的计算机体系结构和操作系统,其中包括微软公司.NET 环境下的基于JIT 的系统以及硬件设计上的Crusoe 处理器。
优缺点
优点
动态编译从科学和商业角度来看有如下的优点:
(1)性能提高:由于编译过程包含在运行过程中,因此可以根据运行时具体程序的特点对每个程序分别进行优化,这比静态的编译器针对所有程序作统一优化更有效。我们可以在程序员未知的情况下进行动态优化和简档引导的(profile-guided)优化。
(2)软件形态:目标机在没有动态编译器的条件下是不能运行非目标机软件的,动态编译器在这里充当了软件层的作用,也就是在操作系统之上建立一层软件平台,通过该平台对源程序的翻译,从而得到能够在目标机上运行的代码。由于动态编译通过软件实现,因此减少了硬件设计的难度,增加了软件的灵活性。
(3)硬件复杂度降低:普通的超标量机往往把计算结果一遍遍地重复放到内存中,不但浪费了计算资源,还占用了相当多的计算时间。用动态编译器可以轻松地解决上述问题。动态编译器只对相同代码翻译和优化一遍,然后将目标代码存储在内存中,每次执行时不用像硬件那样重复进行代码优化工作。
(4)遗留代码的新生:许多年前的遗留代码由于“年久失修”,其性能已经大大下降。从源程序角度进行维护已经毫无意义。动态编译技术的出现使得原来的遗留代码可以重新进行编译,并在新的体系结构上运行。对它们来说,不啻为一种“新生”。
(5)加快软件发布的速度:在新的体系结构上开发软件总是一件麻烦的事情,往往需要结合其新的优点重新设计开发。动态编译技术的出现彻底解决了这个问题,它不仅消除了软件重新开发的问题,还加快了软件发布的速度,提高了软件在新的体系结构上的性能。
(6)扩展了软件优化的空间:传统的软件优化技术总是着眼于局部的、静态的优化。动态编译技术的出现带动了软件优化技术的发展,针对间接跳转、函数返回、共享库、系统调用等等都逐步形成了新的优化技术。
(7)改善了存储系统的使用:一般的程序都有相当多的跳转,经常造成颠簸现象,导致存储系统性能下降,从而影响了软件的整体性能。动态编译技术能够消除不必要的跳转,改善目标代码的分布情况,更好地利用目标机存储系统的特点,节省访存时间,提高指令高速缓存的性能。
(8)改正硬件的错误:某些处理器问世以来,会发现许多新的错误。对用户而言,不断更换新的硬件是一笔昂贵的开销。有些硬件错误可以通过动态编译器来解决。例如,某些硬件不支持某条指令,或是错误地实现了某条指令。通过动态编译器的重新实现可以完全解决上述问题。
(9)推进处理器的发展:动态编译器从某种程度上可以代替硬件。因此芯片上可以腾出不少空间实现复杂的电路、增加处理器核、扩大高速缓存的容量。这些手段都推进了处理器的发展。
缺点
动态编译不可避免地有如下缺点,在设计动态编译器时必须尽可能地减少这些因素对动态编译器正确性和性能的影响。
(1)占用额外的运行时间:动态编译,顾名思义就是在运行时进行编译,很显然动态编译会占用额外的运行时间。
(2)占用额外的内存资源:动态编译的结果必须存储在内存中才能被执行(除非完全采用解释执行),这就占用了机器额外的内存资源。
(3)初次执行的代码效率很低:动态编译器在第一次遇到代码时,必须先翻译后执行,因此会造成性能的低下。通常一个程序刚被启动是动态编译器效率最低的时候。
(4)动态编译程序的调试很困难:由于动态编译器编译后代码的地址同源程序中的地址是不同的。因此调试起来必须注意译前译后地址的转换,稍有不慎就容易引起调试失败。
动态编译器的设计
动态编译器的设计思想和静态编译器有较大的不同。它没有静态编译器那样复杂的编译过程,但是它在编译方式、模拟方式、编译范围、体系结构的选择方面比静态编译器灵活、复杂。
出于性能的考虑,动态编译器的设计架构不仅要考虑编译代码的正确性,还要同时关注代码的执行性能。因此在设计中必须为将来可能的性能优化留出接口,数据结构的组织和通用算法的安排都需要把性能因素考虑在内。
设计难点
尽管动态编译器有许多优点,设计上也有相当大的弹性。然而成功设计一个有实际价值的动态编译器还面临着相当大的难题。纵观现有的动态编译器,主要难点如下:
(1)自修改代码:
Henry Massalin 是自修改代码之父。他最早发现并指出了自修改代码对Java 虚拟器的影响。同样,自修改代码对动态编译器也是一个棘手的问题。所谓自修改代码就是在程序运行过程中出于某种目的能够修改自身代码的代码。这种目的可能是运行时生成代码,也可能是子函数调用的回补,甚至可能是优化某个与状态无关的循环。以Windows 系统为例,有一个段寄存器同时包含了数据和代码,它往往就是自修改代码产生的根源。由于数据段、代码段和堆栈段的属性各不相同,数据段可读可写,代码段可读可执行,堆栈段可读可写可执行,因此自修改代码利用不同段的特性修改自身代码从而达到需要的效果。
动态编译器必须能够对操作系统加载和卸载的不同程序进行翻译。当源程序中含有自修改代码时,它不可避免地在满足某些条件时(往往是执行了某条指令后)修改自身的代码。对动态编译器而言,这是十分危险的动作。动态编译器不仅应该知道代码已经被修改,还必须知道是哪些代码被修改了。无论是哪种情况,都必须对翻译后的相应目标代码作无效处理。由于动态编译器没有操作系统的功能,因此自修改代码的执行并不会通知动态编译器,所以任何一个能处理自修改代码的动态编译器都得主动检查段属性,从而发现自修改代码,进行相应的处理。
(2)精确异常:
在一个以优化性能为主要目的的流水线中(或者是用于指令并行执行的设计中),系统的顺序执行只是一种抽象。如果硬件不是设计得特别聪明,中断使我们看到程序不是顺序执行的。当一个异常发生,系统的顺序执行被中断时,将会有几条指令处于流水线的不同阶段。因为我们不想中断处理破坏程序的正常执行,对于没有执行完的指令,我们必需记住它们执行到哪一个阶段,以便在中断处理之后能恢复程序执行。
如果处理器是精确异常的,那么异常的软件处理就会很简单。对于一个精确异常的处理器,在发生异常时,我们都会有一个引起异常的指令。该指令前面的所有指令都以执行完,该指令以及该指令以后的指令都不会有任何软件值得考虑的负作用。所以软件作异常处理时,可以完全忽略指令的乱序执行。
异常发生的顺序与指令的顺序相同。在非流水线的处理器上,这是显而易见的。然而在流水线的处理器上,异常可能会发生在指令执行的不同阶段,从而产生潜在的问题。比如,如果一个读内存指令产生一个地址异常,这个异常一直要到读写内存阶段才产生。如果它的后一条指令在取指阶段就产生错误,则后一条指令会想产生异常,从而破坏异常发生的顺序跟指令的顺序相同这个约定。为了避免这个问题,被发现的异常情况一直要到确认有异常情况的指令的前面的所有指令都不产生异常时才产生异常。在发现异常情况时,该情况只是被记下来沿着流水线传递下去直到某一级。如果在这个过程中以前的指令产生的异常被发现,该异常情况仅仅被简单的忽略掉,从而解决了整个问题。
当然对动态编译器来说,页错误、异步异常之类的计时器中断会提供一个当前机器执行的一致状态,得到这个一直状态之后,动态编译器可以模拟源体系结构上异常处理器的行为,从而在目标体系结构上精确重现这个异常。
(3)地址转换:
把一个虚地址翻译成物理地址时,处理器必须先得出虚页号和偏移量。处理器使用虚页号作为检索进程页表记录的索引。如果对应那偏移量的页表记录是有效的,处理器就从中拿出物理页号。如果记录是无效的,表明进程想存取一个不在物理内存中的地址。在这种情况下,处理器不能翻译这个虚地址,而必须把控制权传给操作系统,让它处理。当当前进程试图存取一个处理器无法翻译的虚地址时,处理器引发一个“页错误”,并将产生页错误的虚地址和原因告诉给操作系统。假设找到的是一有效的页表记录,处理器就取出物理页号并且乘以页的大小,得到内存中页的基地址。最后,处理器加上偏移量得到它需要指令或数据的地址。
可见,动态编译器必须能够处理这种情况:当指令计算出的虚拟地址所映射的物理地址并不是真正含有某个正确值的地址,或者当前进程试图存取一个处理器无法
翻译的虚地址导致处理器引发一个“页错误”。当然,还可能有更复杂的情况,比如,
在内存映射的输入输出中, 某些地址是不可缓存的。无论哪种情况,动态编译器必
须首先将其识别,然后采用某种机制加以解决。这是动态编译器不得不面对的问题。
(4)自引用代码
自引用代码把指令流作为数据进行处理,其典型应用就是计算自身的校验和,从而保证程序没有因为某些原因被损坏。动态编译器必须能够让自引用代码正确运行。一般我们通过在源地址空间中保留一段翻译后的自引用代码来解决这个问题。现在几乎所有的动态编译器都能很好地处理这个问题。
(5)翻译高速缓存的管理
把经常使用的翻译结果保存在内存里可以获得更加高的效率。这块特别的内存区域被命名为翻译高速缓存,它允许代码融合软件的重新使用,并消除冗余的代码。在遇到了以前曾经翻译的源指令顺序,代码冗余软件会忽略翻译的进程并直接执行在翻译缓存的缓存翻译结果。
由于翻译高速缓存的大小是有限的,不可能把所有的翻译结果都放在翻译高速缓存中。当翻译高速缓存全部用完之后,新翻译的结果就必须逐步替换以前翻译的结果。同样,如果以前翻译的结果由于某些原因,如自修改代码,必须被无效的时候,翻译高速缓存也必须体现出这个变化。
翻译高速缓存缓存和重新使用翻译在日常的工作中会高度重复出现。代码冗余软件使用在翻译缓存和优化的单个翻译来匹配重复执行的工作,这样在最少的开销下获得了全速。早期翻译的花费被后面重复的执行分次还清了。
翻译高速缓存的替换策略也是多种多样。总的思想还是只有两种。一是翻译高速缓存用完以后对其中存储的内容全部替换,二是用垃圾回收(garbage collection)算法维护高速缓存的正确性,当然垃圾回收算法有各种变形,不同的动态编译器根据实际需要选择合适的垃圾回收算法。
设计架构
动态编译器是连接两种体系结构的编译器,让其中一个体系结构上的二进制代码经过翻译以后运行在另一个体系结构上,所以动态编译器中必然包含两种不同的体系结构。其中被翻译的那个体系结构成为源体系结构(source architecture),在这个体系结构上编译的程序是动态编译器的输入;而在底层实际运行,使得二进制代码能够正确运行的那个体系结构,我们称之为目标体系结构(target architecture)。图表述了动态编译器的运行环境。
根据程序的局部性原理,即程序在执行时所呈现的局部性规律,即在一段较短时间内,程序的执行仅限于某个部分。相应地,它所访问的存储器空间也局限在某个空间。当硬件发展的速度大大加快的时候,动态编译器的优化机会也相应增加,所以我们可以利用反馈指导的优化思想识别出执行最频繁的代码,并对这些频繁代码进行特殊的优化。
这样一来,动态编译器的基本结构就很明朗了。我们把动态编译器的编译过程分为两个阶段。第一个阶段是普通代码,只需要逐条翻译,在翻译过程中记录下代码的执行频率,也就是将来可能成为频繁代码的代码段;第二个阶段是频繁代码,也就是我们准备充分优化的代码。在这两个阶段以外的工作,我们可以放到编译动态编译器的过程中完成,这就完全避免了运行时可能造成的代价了。
全国各地天气预报查询

上海市

  • 市辖区
  • 云南省

  • 临沧市
  • 云南省

  • 丽江市
  • 云南省

  • 保山市
  • 云南省

  • 大理白族自治州
  • 云南省

  • 德宏傣族景颇族自治州
  • 云南省

  • 怒江傈僳族自治州
  • 云南省

  • 文山壮族苗族自治州
  • 云南省

  • 昆明市
  • 云南省

  • 昭通市
  • 云南省

  • 普洱市
  • 云南省

  • 曲靖市
  • 云南省

  • 楚雄彝族自治州
  • 云南省

  • 玉溪市
  • 云南省

  • 红河哈尼族彝族自治州
  • 云南省

  • 西双版纳傣族自治州
  • 云南省

  • 迪庆藏族自治州
  • 内蒙古自治区

  • 乌兰察布市
  • 内蒙古自治区

  • 乌海市
  • 内蒙古自治区

  • 兴安盟
  • 内蒙古自治区

  • 包头市
  • 内蒙古自治区

  • 呼伦贝尔市
  • 内蒙古自治区

  • 呼和浩特市
  • 内蒙古自治区

  • 巴彦淖尔市
  • 内蒙古自治区

  • 赤峰市
  • 内蒙古自治区

  • 通辽市
  • 内蒙古自治区

  • 鄂尔多斯市
  • 内蒙古自治区

  • 锡林郭勒盟
  • 内蒙古自治区

  • 阿拉善盟
  • 北京市

  • 市辖区
  • 吉林省

  • 吉林市
  • 吉林省

  • 四平市
  • 吉林省

  • 延边朝鲜族自治州
  • 吉林省

  • 松原市
  • 吉林省

  • 白城市
  • 吉林省

  • 白山市
  • 吉林省

  • 辽源市
  • 吉林省

  • 通化市
  • 吉林省

  • 长春市
  • 四川省

  • 乐山市
  • 四川省

  • 内江市
  • 四川省

  • 凉山彝族自治州
  • 四川省

  • 南充市
  • 四川省

  • 宜宾市
  • 四川省

  • 巴中市
  • 四川省

  • 广元市
  • 四川省

  • 广安市
  • 四川省

  • 德阳市
  • 四川省

  • 成都市
  • 四川省

  • 攀枝花市
  • 四川省

  • 泸州市
  • 四川省

  • 甘孜藏族自治州
  • 四川省

  • 眉山市
  • 四川省

  • 绵阳市
  • 四川省

  • 自贡市
  • 四川省

  • 资阳市
  • 四川省

  • 达州市
  • 四川省

  • 遂宁市
  • 四川省

  • 阿坝藏族羌族自治州
  • 四川省

  • 雅安市
  • 天津市

  • 市辖区
  • 宁夏回族自治区

  • 中卫市
  • 宁夏回族自治区

  • 吴忠市
  • 宁夏回族自治区

  • 固原市
  • 宁夏回族自治区

  • 石嘴山市
  • 宁夏回族自治区

  • 银川市
  • 安徽省

  • 亳州市
  • 安徽省

  • 六安市
  • 安徽省

  • 合肥市
  • 安徽省

  • 安庆市
  • 安徽省

  • 宣城市
  • 安徽省

  • 宿州市
  • 安徽省

  • 池州市
  • 安徽省

  • 淮北市
  • 安徽省

  • 淮南市
  • 安徽省

  • 滁州市
  • 安徽省

  • 芜湖市
  • 安徽省

  • 蚌埠市
  • 安徽省

  • 铜陵市
  • 安徽省

  • 阜阳市
  • 安徽省

  • 马鞍山市
  • 安徽省

  • 黄山市
  • 山东省

  • 东营市
  • 山东省

  • 临沂市
  • 山东省

  • 威海市
  • 山东省

  • 德州市
  • 山东省

  • 日照市
  • 山东省

  • 枣庄市
  • 山东省

  • 泰安市
  • 山东省

  • 济南市
  • 山东省

  • 济宁市
  • 山东省

  • 淄博市
  • 山东省

  • 滨州市
  • 山东省

  • 潍坊市
  • 山东省

  • 烟台市
  • 山东省

  • 聊城市
  • 山东省

  • 菏泽市
  • 山东省

  • 青岛市
  • 山西省

  • 临汾市
  • 山西省

  • 吕梁市
  • 山西省

  • 大同市
  • 山西省

  • 太原市
  • 山西省

  • 忻州市
  • 山西省

  • 晋中市
  • 山西省

  • 晋城市
  • 山西省

  • 朔州市
  • 山西省

  • 运城市
  • 山西省

  • 长治市
  • 山西省

  • 阳泉市
  • 广东省

  • 东莞市
  • 广东省

  • 中山市
  • 广东省

  • 云浮市
  • 广东省

  • 佛山市
  • 广东省

  • 广州市
  • 广东省

  • 惠州市
  • 广东省

  • 揭阳市
  • 广东省

  • 梅州市
  • 广东省

  • 汕头市
  • 广东省

  • 汕尾市
  • 广东省

  • 江门市
  • 广东省

  • 河源市
  • 广东省

  • 深圳市
  • 广东省

  • 清远市
  • 广东省

  • 湛江市
  • 广东省

  • 潮州市
  • 广东省

  • 珠海市
  • 广东省

  • 肇庆市
  • 广东省

  • 茂名市
  • 广东省

  • 阳江市
  • 广东省

  • 韶关市
  • 广西壮族自治区

  • 北海市
  • 广西壮族自治区

  • 南宁市
  • 广西壮族自治区

  • 崇左市
  • 广西壮族自治区

  • 来宾市
  • 广西壮族自治区

  • 柳州市
  • 广西壮族自治区

  • 桂林市
  • 广西壮族自治区

  • 梧州市
  • 广西壮族自治区

  • 河池市
  • 广西壮族自治区

  • 玉林市
  • 广西壮族自治区

  • 百色市
  • 广西壮族自治区

  • 贵港市
  • 广西壮族自治区

  • 贺州市
  • 广西壮族自治区

  • 钦州市
  • 广西壮族自治区

  • 防城港市
  • 新疆维吾尔自治区

  • 乌鲁木齐市
  • 新疆维吾尔自治区

  • 伊犁哈萨克自治州
  • 新疆维吾尔自治区

  • 克孜勒苏柯尔克孜自治州
  • 新疆维吾尔自治区

  • 克拉玛依市
  • 新疆维吾尔自治区

  • 博尔塔拉蒙古自治州
  • 新疆维吾尔自治区

  • 吐鲁番市
  • 新疆维吾尔自治区

  • 和田地区
  • 新疆维吾尔自治区

  • 哈密市
  • 新疆维吾尔自治区

  • 喀什地区
  • 新疆维吾尔自治区

  • 塔城地区
  • 新疆维吾尔自治区

  • 巴音郭楞蒙古自治州
  • 新疆维吾尔自治区

  • 昌吉回族自治州
  • 新疆维吾尔自治区

  • 自治区直辖县级行政区划
  • 新疆维吾尔自治区

  • 阿克苏地区
  • 新疆维吾尔自治区

  • 阿勒泰地区
  • 江苏省

  • 南京市
  • 江苏省

  • 南通市
  • 江苏省

  • 宿迁市
  • 江苏省

  • 常州市
  • 江苏省

  • 徐州市
  • 江苏省

  • 扬州市
  • 江苏省

  • 无锡市
  • 江苏省

  • 泰州市
  • 江苏省

  • 淮安市
  • 江苏省

  • 盐城市
  • 江苏省

  • 苏州市
  • 江苏省

  • 连云港市
  • 江苏省

  • 镇江市
  • 江西省

  • 上饶市
  • 江西省

  • 九江市
  • 江西省

  • 南昌市
  • 江西省

  • 吉安市
  • 江西省

  • 宜春市
  • 江西省

  • 抚州市
  • 江西省

  • 新余市
  • 江西省

  • 景德镇市
  • 江西省

  • 萍乡市
  • 江西省

  • 赣州市
  • 江西省

  • 鹰潭市
  • 河北省

  • 保定市
  • 河北省

  • 唐山市
  • 河北省

  • 廊坊市
  • 河北省

  • 张家口市
  • 河北省

  • 承德市
  • 河北省

  • 沧州市
  • 河北省

  • 石家庄市
  • 河北省

  • 秦皇岛市
  • 河北省

  • 衡水市
  • 河北省

  • 邢台市
  • 河北省

  • 邯郸市
  • 河南省

  • 三门峡市
  • 河南省

  • 信阳市
  • 河南省

  • 南阳市
  • 河南省

  • 周口市
  • 河南省

  • 商丘市
  • 河南省

  • 安阳市
  • 河南省

  • 平顶山市
  • 河南省

  • 开封市
  • 河南省

  • 新乡市
  • 河南省

  • 洛阳市
  • 河南省

  • 漯河市
  • 河南省

  • 濮阳市
  • 河南省

  • 焦作市
  • 河南省

  • 省直辖县级行政区划
  • 河南省

  • 许昌市
  • 河南省

  • 郑州市
  • 河南省

  • 驻马店市
  • 河南省

  • 鹤壁市
  • 浙江省

  • 丽水市
  • 浙江省

  • 台州市
  • 浙江省

  • 嘉兴市
  • 浙江省

  • 宁波市
  • 浙江省

  • 杭州市
  • 浙江省

  • 温州市
  • 浙江省

  • 湖州市
  • 浙江省

  • 绍兴市
  • 浙江省

  • 舟山市
  • 浙江省

  • 衢州市
  • 浙江省

  • 金华市
  • 海南省

  • 三亚市
  • 海南省

  • 三沙市
  • 海南省

  • 儋州市
  • 海南省

  • 海口市
  • 海南省

  • 省直辖县级行政区划
  • 湖北省

  • 十堰市
  • 湖北省

  • 咸宁市
  • 湖北省

  • 孝感市
  • 湖北省

  • 宜昌市
  • 湖北省

  • 恩施土家族苗族自治州
  • 湖北省

  • 武汉市
  • 湖北省

  • 省直辖县级行政区划
  • 湖北省

  • 荆州市
  • 湖北省

  • 荆门市
  • 湖北省

  • 襄阳市
  • 湖北省

  • 鄂州市
  • 湖北省

  • 随州市
  • 湖北省

  • 黄冈市
  • 湖北省

  • 黄石市
  • 湖南省

  • 娄底市
  • 湖南省

  • 岳阳市
  • 湖南省

  • 常德市
  • 湖南省

  • 张家界市
  • 湖南省

  • 怀化市
  • 湖南省

  • 株洲市
  • 湖南省

  • 永州市
  • 湖南省

  • 湘潭市
  • 湖南省

  • 湘西土家族苗族自治州
  • 湖南省

  • 益阳市
  • 湖南省

  • 衡阳市
  • 湖南省

  • 邵阳市
  • 湖南省

  • 郴州市
  • 湖南省

  • 长沙市
  • 甘肃省

  • 临夏回族自治州
  • 甘肃省

  • 兰州市
  • 甘肃省

  • 嘉峪关市
  • 甘肃省

  • 天水市
  • 甘肃省

  • 定西市
  • 甘肃省

  • 平凉市
  • 甘肃省

  • 庆阳市
  • 甘肃省

  • 张掖市
  • 甘肃省

  • 武威市
  • 甘肃省

  • 甘南藏族自治州
  • 甘肃省

  • 白银市
  • 甘肃省

  • 酒泉市
  • 甘肃省

  • 金昌市
  • 甘肃省

  • 陇南市
  • 福建省

  • 三明市
  • 福建省

  • 南平市
  • 福建省

  • 厦门市
  • 福建省

  • 宁德市
  • 福建省

  • 泉州市
  • 福建省

  • 漳州市
  • 福建省

  • 福州市
  • 福建省

  • 莆田市
  • 福建省

  • 龙岩市
  • 西藏自治区

  • 山南市
  • 西藏自治区

  • 拉萨市
  • 西藏自治区

  • 日喀则市
  • 西藏自治区

  • 昌都市
  • 西藏自治区

  • 林芝市
  • 西藏自治区

  • 那曲市
  • 西藏自治区

  • 阿里地区
  • 贵州省

  • 六盘水市
  • 贵州省

  • 安顺市
  • 贵州省

  • 毕节市
  • 贵州省

  • 贵阳市
  • 贵州省

  • 遵义市
  • 贵州省

  • 铜仁市
  • 贵州省

  • 黔东南苗族侗族自治州
  • 贵州省

  • 黔南布依族苗族自治州
  • 贵州省

  • 黔西南布依族苗族自治州
  • 辽宁省

  • 丹东市
  • 辽宁省

  • 大连市
  • 辽宁省

  • 抚顺市
  • 辽宁省

  • 朝阳市
  • 辽宁省

  • 本溪市
  • 辽宁省

  • 沈阳市
  • 辽宁省

  • 盘锦市
  • 辽宁省

  • 营口市
  • 辽宁省

  • 葫芦岛市
  • 辽宁省

  • 辽阳市
  • 辽宁省

  • 铁岭市
  • 辽宁省

  • 锦州市
  • 辽宁省

  • 阜新市
  • 辽宁省

  • 鞍山市
  • 重庆市

  • 重庆市

  • 市辖区
  • 陕西省

  • 咸阳市
  • 陕西省

  • 商洛市
  • 陕西省

  • 安康市
  • 陕西省

  • 宝鸡市
  • 陕西省

  • 延安市
  • 陕西省

  • 榆林市
  • 陕西省

  • 汉中市
  • 陕西省

  • 渭南市
  • 陕西省

  • 西安市
  • 陕西省

  • 铜川市
  • 青海省

  • 果洛藏族自治州
  • 青海省

  • 海东市
  • 青海省

  • 海北藏族自治州
  • 青海省

  • 海南藏族自治州
  • 青海省

  • 海西蒙古族藏族自治州
  • 青海省

  • 玉树藏族自治州
  • 青海省

  • 西宁市
  • 青海省

  • 黄南藏族自治州
  • 黑龙江省

  • 七台河市
  • 黑龙江省

  • 伊春市
  • 黑龙江省

  • 佳木斯市
  • 黑龙江省

  • 双鸭山市
  • 黑龙江省

  • 哈尔滨市
  • 黑龙江省

  • 大兴安岭地区
  • 黑龙江省

  • 大庆市
  • 黑龙江省

  • 牡丹江市
  • 黑龙江省

  • 绥化市
  • 黑龙江省

  • 鸡西市
  • 黑龙江省

  • 鹤岗市
  • 黑龙江省

  • 黑河市
  • 黑龙江省

  • 齐齐哈尔市