文章目录
[JVM CMS垃圾收集器 系统性知识体系总结](#JVM CMS垃圾收集器 系统性知识体系总结)
一、CMS概述与定位
二、CMS核心原理
[2.1 并发执行的本质](#2.1 并发执行的本质)
[2.2 三色标记法(并发标记的基础)](#2.2 三色标记法(并发标记的基础))
[2.3 增量更新(Incremental Update)解决方案](#2.3 增量更新(Incremental Update)解决方案)
三、CMS完整回收流程(7个阶段)
[阶段1:初始标记(Initial Mark)- STW](#阶段1:初始标记(Initial Mark)- STW)
[阶段2:并发标记(Concurrent Mark)- 并发](#阶段2:并发标记(Concurrent Mark)- 并发)
[阶段3:并发预清理(Concurrent Preclean)- 并发](#阶段3:并发预清理(Concurrent Preclean)- 并发)
[阶段4:并发可中断预清理(Concurrent Abortable Preclean)- 并发](#阶段4:并发可中断预清理(Concurrent Abortable Preclean)- 并发)
[阶段5:最终标记(Final Remark)- STW](#阶段5:最终标记(Final Remark)- STW)
[阶段6:并发清除(Concurrent Sweep)- 并发](#阶段6:并发清除(Concurrent Sweep)- 并发)
[阶段7:并发重置(Concurrent Reset)- 并发](#阶段7:并发重置(Concurrent Reset)- 并发)
四、CMS核心优缺点分析
[4.1 显著优点](#4.1 显著优点)
[4.2 致命缺点](#4.2 致命缺点)
五、CMS被废弃的根本原因
[5.1 设计缺陷无法根本解决](#5.1 设计缺陷无法根本解决)
[5.2 G1收集器的全面超越](#5.2 G1收集器的全面超越)
[5.3 维护成本过高](#5.3 维护成本过高)
六、补充知识:CMS关键参数调优
七、总结
[CMS垃圾收集器 面试问答卡片(可直接背诵)](#CMS垃圾收集器 面试问答卡片(可直接背诵))
一、基础概念类
Q1:什么是CMS垃圾收集器?它的设计目标和适用场景是什么?
[Q2:CMS和传统收集器(如Serial Old)最本质的区别是什么?](#Q2:CMS和传统收集器(如Serial Old)最本质的区别是什么?)
二、核心原理类
Q3:CMS使用什么算法实现并发标记?它将对象分为哪几类?
Q4:并发标记阶段会产生什么核心问题?CMS是如何解决的?
三、回收流程类
Q5:CMS完整的回收流程分为哪7个阶段?哪些是STW阶段?
Q6:请简述CMS每个核心阶段的主要任务和特点
四、优缺点类
Q7:CMS有哪些显著的优点?
Q8:CMS有哪些致命的缺点?(高频考点)
Q9:什么是CMS的"并发模式失败"?它会导致什么后果?
五、废弃原因类
Q10:CMS为什么会被废弃?它在哪个JDK版本被标记为废弃,哪个版本被完全移除?
六、调优参数类
Q11:列举5个CMS最常用的调优参数及其作用
[CMS vs G1 垃圾收集器 对比面试问答卡片(高频考点)](#CMS vs G1 垃圾收集器 对比面试问答卡片(高频考点))
一、基础定位与核心差异类
Q1:CMS和G1最根本的区别是什么?
Q2:CMS和G1分别在哪个JDK版本成为默认收集器?
二、核心原理对比类
Q3:CMS和G1使用的核心垃圾回收算法有什么不同?
Q4:CMS和G1解决并发标记对象丢失问题的方案有什么不同?
三、回收流程对比类
Q5:CMS和G1的回收流程有什么本质区别?
[Q6:什么是G1的Mixed GC?它和CMS的老年代GC有什么不同?](#Q6:什么是G1的Mixed GC?它和CMS的老年代GC有什么不同?)
四、性能与问题对比类
Q7:CMS和G1在停顿时间方面有什么差异?
Q8:CMS的"并发模式失败"和G1的"疏散失败"有什么区别?
Q9:CMS和G1在处理大对象方面有什么不同?
五、适用场景与调优对比类
Q10:CMS和G1分别适用于什么场景?
Q11:CMS和G1最核心的调优参数分别是什么?
六、总结对比表(面试速记)
JVM CMS垃圾收集器 系统性知识体系总结
一、CMS概述与定位
Concurrent Mark Sweep(并发标记清除) 是HotSpot虚拟机在JDK 1.5时期推出的并发低延迟垃圾收集器,也是JVM历史上第一个真正意义上实现垃圾回收线程与用户线程并发执行的收集器。
设计目标 :最短回收停顿时间(Stop-The-World, STW),优先满足响应速度要求
适用场景:互联网Web应用、B/S系统、桌面GUI应用等对用户体验敏感的系统
作用范围 :老年代(需配合年轻代的Serial或ParNew收集器使用)
核心算法 :标记-清除(Mark-Sweep) 算法(并发版本)
二、CMS核心原理
2.1 并发执行的本质
CMS通过将耗时最长的标记和清除阶段与用户线程并发执行,大幅缩短单次STW时间。它使用多线程并行处理垃圾回收任务,充分利用多核CPU资源。
2.2 三色标记法(并发标记的基础)
CMS使用三色标记法实现并发标记,将对象分为三类:
白色:未被垃圾收集器访问过(初始状态,最终会被回收)
灰色:已被访问过,但至少有一个引用未被扫描
黑色:已被访问过,且所有引用都已扫描完毕(存活对象)
并发标记的核心问题 :用户线程在标记过程中修改引用关系,可能导致对象丢失(原本存活的对象被误标为白色)。
2.3 增量更新(Incremental Update)解决方案
CMS采用增量更新算法解决并发标记时的对象丢失问题:
当一个黑色对象 新增了对白色对象 的引用时,将这个黑色对象重新标记为灰色
在最终重新标记阶段,会重新扫描所有灰色对象,确保所有存活对象都被正确标记
原理:破坏了"黑色对象不会引用白色对象"的对象丢失条件,保证了标记的准确性。
三、CMS完整回收流程(7个阶段)
CMS的回收过程分为4个STW阶段 和3个并发阶段,按执行顺序排列:
阶段1:初始标记(Initial Mark)- STW
耗时:极短(毫秒级)
任务 :只标记GC Roots直接关联的对象
特点:单线程执行(JDK 1.6后改为多线程),停顿时间与堆大小无关,只与GC Roots数量有关
阶段2:并发标记(Concurrent Mark)- 并发
耗时:最长(与堆中存活对象数量成正比)
任务 :从初始标记的对象出发,遍历整个对象图,标记所有存活对象
特点:与用户线程完全并发执行,不产生停顿;但标记结果可能不准确(用户线程修改了引用)
阶段3:并发预清理(Concurrent Preclean)- 并发
耗时:较短
任务 :
处理并发标记阶段产生的脏卡(Dirty Card)
标记从年轻代晋升到老年代的对象
提前处理部分引用变化,减轻后续重新标记阶段的负担
特点:可通过参数控制执行时间,目的是缩短最终重新标记的STW时间
阶段4:并发可中断预清理(Concurrent Abortable Preclean)- 并发
耗时:可配置(默认最多5秒)
任务:与并发预清理类似,但可以被中断
特点:等待年轻代发生Minor GC,因为年轻代GC后老年代的引用会更稳定,能进一步减少重新标记的工作量
阶段5:最终标记(Final Remark)- STW
耗时:中等(比初始标记长,但远短于并发标记)
任务 :
修正并发标记阶段因用户线程修改引用导致的标记错误
重新扫描所有GC Roots
处理增量更新记录的引用变化
特点 :多线程并行执行,是CMS整个回收过程中第二长的停顿
阶段6:并发清除(Concurrent Sweep)- 并发
耗时:较长(与垃圾数量成正比)
任务:清除所有被标记为垃圾的对象,释放内存空间
特点:与用户线程并发执行;不移动存活对象,直接回收垃圾内存
阶段7:并发重置(Concurrent Reset)- 并发
耗时:极短
任务:重置CMS收集器的内部数据结构,为下一次垃圾回收做准备
特点:与用户线程并发执行,不影响应用性能
四、CMS核心优缺点分析
4.1 显著优点
低延迟:将90%以上的工作放在并发阶段执行,STW时间极短(通常在几十毫秒以内)
高并发:充分利用多核CPU资源,垃圾回收与应用程序同时运行
响应迅速:特别适合对用户体验要求高的交互式应用
成熟稳定:经过多年生产环境验证,调优经验丰富
4.2 致命缺点
CPU资源消耗大
并发阶段会占用大量CPU线程(默认占用CPU核心数的1/4)
在CPU核心数较少的服务器上(如2核),会严重影响应用程序的吞吐量
当CPU负载较高时,并发回收的效率会急剧下降
内存碎片问题
基于标记-清除算法,回收后会产生大量不连续的内存碎片
碎片过多会导致大对象无法分配,提前触发Full GC
虽然提供了-XX:+UseCMSCompactAtFullCollection参数进行压缩,但压缩阶段会产生长时间STW
并发模式失败(Concurrent Mode Failure)
并发清除阶段,用户线程仍在运行,会产生新的垃圾(称为"浮动垃圾")
如果老年代剩余空间不足以容纳浮动垃圾,会触发并发模式失败
此时CMS会退化为Serial Old收集器 ,进行单线程Full GC,产生极长的STW停顿(可能长达数秒甚至数十秒)
无法处理浮动垃圾
并发标记和清除阶段产生的新垃圾,只能等到下一次GC才能回收
因此CMS需要预留一部分内存空间给浮动垃圾使用(默认老年代使用率达到68%时触发GC)
预留空间过小会导致并发模式失败,过大则会浪费内存
五、CMS被废弃的根本原因
CMS在JDK 9中被标记为废弃(Deprecated) ,在JDK 14中被完全移除,主要原因如下:
5.1 设计缺陷无法根本解决
内存碎片问题:这是标记-清除算法的固有缺陷,无论如何调优都无法彻底解决
并发模式失败风险:始终存在退化为Serial Old的可能,这是生产环境的重大隐患
CPU资源占用:在低配置服务器上表现极差,无法适应现代多核CPU的发展趋势
5.2 G1收集器的全面超越
G1(Garbage-First)收集器在JDK 7中正式推出,在JDK 9中成为默认收集器,全面取代了CMS:
统一收集年轻代和老年代:不需要配合其他收集器使用,简化了JVM配置
基于Region的内存布局:将堆划分为多个大小相等的Region,解决了内存碎片问题
可预测的停顿时间模型:用户可以指定最大停顿时间,G1会尽量满足
并行与并发结合:既利用多核CPU,又保持低延迟
整体标记-整理,局部复制:兼顾了吞吐量和内存利用率
5.3 维护成本过高
CMS的代码非常复杂,维护难度大
随着JVM的发展,CMS与其他新特性(如ZGC、Shenandoah)的兼容性越来越差
Oracle将开发资源集中在更先进的G1、ZGC和Shenandoah收集器上
六、补充知识:CMS关键参数调优
参数
作用
默认值
-XX:+UseConcMarkSweepGC
启用CMS收集器
JDK 8及之前非服务器模式默认
-XX:ParallelGCThreads
并行阶段的线程数
CPU核心数
-XX:ConcGCThreads
并发阶段的线程数
ParallelGCThreads/4
-XX:CMSInitiatingOccupancyFraction
老年代使用率达到多少时触发GC
68%
-XX:+UseCMSCompactAtFullCollection
Full GC时进行内存压缩
JDK 8默认开启
-XX:CMSFullGCsBeforeCompaction
多少次Full GC后进行一次压缩
0(每次都压缩)
-XX:+CMSParallelRemarkEnabled
启用并行最终标记
默认开启
七、总结
CMS是JVM垃圾回收技术发展史上的里程碑式产品,它首次实现了并发垃圾回收,解决了传统收集器停顿时间过长的问题,为互联网应用的发展做出了巨大贡献。
然而,由于其基于标记-清除算法的固有缺陷,以及G1等新一代收集器的出现,CMS最终被淘汰。但CMS的设计思想(并发标记、增量更新等)对后续收集器的发展产生了深远影响,是学习JVM垃圾回收机制不可或缺的重要内容。
CMS垃圾收集器 面试问答卡片(可直接背诵)
一、基础概念类
Q1:什么是CMS垃圾收集器?它的设计目标和适用场景是什么?
A:
CMS全称Concurrent Mark Sweep(并发标记清除) ,是HotSpot在JDK1.5推出的第一个真正意义上的并发低延迟收集器
设计目标:最短STW停顿时间,优先保证响应速度
适用场景:互联网Web应用、B/S系统、桌面GUI等对用户体验敏感的系统
作用范围:仅老年代,必须配合年轻代的Serial或ParNew收集器使用
核心算法:并发版本的标记-清除算法
Q2:CMS和传统收集器(如Serial Old)最本质的区别是什么?
A :
传统收集器(Serial Old、Parallel Old)在垃圾回收时全程STW ,停顿时间与堆大小成正比;而CMS将90%以上的耗时工作(标记、清除)与用户线程并发执行,仅在几个关键阶段短暂停顿,大幅降低了单次停顿时间。
二、核心原理类
Q3:CMS使用什么算法实现并发标记?它将对象分为哪几类?
A :
CMS使用三色标记法实现并发标记,将对象分为三类:
白色:未被收集器访问过(初始状态,最终会被回收)
灰色:已被访问过,但至少有一个引用未扫描完成
黑色:已被访问过,且所有引用都已扫描完毕(存活对象)
Q4:并发标记阶段会产生什么核心问题?CMS是如何解决的?
A:
核心问题:对象丢失(用户线程在标记过程中修改引用关系,导致原本存活的对象被误标为白色)
解决方案:增量更新(Incremental Update)算法
当一个黑色对象 新增了对白色对象 的引用时,将该黑色对象重新标记为灰色
在最终重新标记阶段,重新扫描所有灰色对象,确保所有存活对象都被正确标记
原理:破坏了"黑色对象不会引用白色对象"的对象丢失必要条件
三、回收流程类
Q5:CMS完整的回收流程分为哪7个阶段?哪些是STW阶段?
A :
CMS回收流程按顺序分为7个阶段,其中4个STW阶段 ,3个并发阶段:
✅ 初始标记(STW,极短)
⚡ 并发标记(并发,最长)
⚡ 并发预清理(并发,较短)
⚡ 并发可中断预清理(并发,可配置)
✅ 最终标记(STW,中等)
⚡ 并发清除(并发,较长)
⚡ 并发重置(并发,极短)
Q6:请简述CMS每个核心阶段的主要任务和特点
A:
初始标记 :只标记GC Roots直接关联的对象;多线程执行,停顿时间与堆大小无关,只与GC Roots数量有关
并发标记:从初始标记对象出发遍历整个对象图;与用户线程完全并发,标记结果可能不准确
并发预清理:处理并发标记产生的脏卡,标记从年轻代晋升的对象;目的是减轻最终标记的负担
并发可中断预清理:与预清理类似,但可中断;等待年轻代Minor GC以进一步减少重新标记工作量
最终标记:修正并发标记阶段的标记错误,重新扫描GC Roots和增量更新记录;是CMS第二长的停顿
并发清除:清除所有标记为垃圾的对象;不移动存活对象,直接回收内存
并发重置:重置内部数据结构,为下一次GC做准备
四、优缺点类
Q7:CMS有哪些显著的优点?
A:
低延迟:绝大多数工作并发执行,STW时间通常控制在几十毫秒以内
高并发:充分利用多核CPU资源,垃圾回收与应用同时运行
响应迅速:特别适合交互式应用,提升用户体验
成熟稳定:经过多年生产环境验证,调优经验丰富
Q8:CMS有哪些致命的缺点?(高频考点)
A:
CPU资源消耗大:并发阶段默认占用1/4的CPU核心数,低配置服务器上会严重影响吞吐量
内存碎片问题:基于标记-清除算法,回收后产生大量不连续碎片,导致大对象无法分配,提前触发Full GC
并发模式失败风险 :并发清除阶段产生的浮动垃圾如果超出预留内存,CMS会退化为Serial Old单线程收集器,产生极长STW停顿(数秒甚至数十秒)
无法处理浮动垃圾:并发阶段产生的新垃圾只能等到下一次GC回收,因此需要预留部分内存,造成浪费
Q9:什么是CMS的"并发模式失败"?它会导致什么后果?
A:
定义:在并发清除阶段,用户线程仍在运行并产生新的垃圾(浮动垃圾),如果老年代剩余空间不足以容纳这些浮动垃圾,就会触发并发模式失败
后果:CMS会立即停止所有并发回收线程,退化为Serial Old单线程收集器 ,对整个老年代进行Full GC,此时会产生极长的STW停顿,是生产环境的重大隐患
五、废弃原因类
Q10:CMS为什么会被废弃?它在哪个JDK版本被标记为废弃,哪个版本被完全移除?
A:
版本:JDK 9中被标记为Deprecated(废弃) ,JDK 14中被完全移除
根本原因:
固有设计缺陷无法解决:标记-清除算法导致的内存碎片、并发模式失败风险、CPU占用高等问题无法从根本上解决
G1收集器的全面超越:G1统一收集年轻代和老年代,基于Region布局解决了碎片问题,支持可预测的停顿时间模型,兼顾吞吐量和延迟
维护成本过高:CMS代码复杂,与JVM新特性兼容性差,Oracle将开发资源转向G1、ZGC和Shenandoah等新一代收集器
六、调优参数类
Q11:列举5个CMS最常用的调优参数及其作用
A:
-XX:+UseConcMarkSweepGC:启用CMS收集器
-XX:CMSInitiatingOccupancyFraction=75:老年代使用率达到75%时触发CMS GC(默认68%)
-XX:+UseCMSCompactAtFullCollection:Full GC时进行内存压缩(JDK8默认开启)
-XX:CMSFullGCsBeforeCompaction=5:每5次Full GC后进行一次压缩(默认0,每次都压缩)
-XX:ConcGCThreads=4:设置并发阶段的GC线程数(默认是ParallelGCThreads/4)
CMS vs G1 垃圾收集器 对比面试问答卡片(高频考点)
一、基础定位与核心差异类
Q1:CMS和G1最根本的区别是什么?
A:
内存布局不同 :CMS采用传统分代式内存布局 (年轻代+老年代连续空间);G1采用Region化内存布局,将整个堆划分为多个大小相等的独立Region(1MB~32MB),每个Region可动态扮演Eden、Survivor或老年代
设计目标不同 :CMS唯一目标是最短停顿时间 ,牺牲了部分吞吐量;G1目标是在可预测的停顿时间内实现高吞吐量,兼顾两者
作用范围不同 :CMS仅收集老年代 ,必须配合年轻代的ParNew/Serial收集器;G1同时收集年轻代和老年代,是全堆收集器
Q2:CMS和G1分别在哪个JDK版本成为默认收集器?
A:
CMS:从未成为过默认收集器,JDK 8及之前服务器模式默认是Parallel Scavenge+Parallel Old
G1:JDK 9及以后的默认垃圾收集器,同时CMS在JDK 9被标记为废弃,JDK 14被完全移除
二、核心原理对比类
Q3:CMS和G1使用的核心垃圾回收算法有什么不同?
A:
CMS :基于标记-清除(Mark-Sweep) 算法
优点:并发执行,停顿时间短
缺点:产生大量内存碎片
G1 :采用**"整体标记-整理,局部复制"** 的混合算法
全局看:基于标记-整理算法,不会产生内存碎片
局部看:回收Region时采用复制算法,将存活对象复制到其他空Region
优点:彻底解决了内存碎片问题,大对象分配更顺畅
Q4:CMS和G1解决并发标记对象丢失问题的方案有什么不同?
A:
CMS :采用增量更新(Incremental Update) 算法
关注引用的新增:当黑色对象新增对白色对象的引用时,将黑色对象重新标记为灰色
最终标记阶段:重新扫描所有灰色对象
G1 :采用原始快照(Snapshot At The Beginning, SATB) 算法
关注引用的删除:当某个对象的引用被删除时,记录下这个引用的原始快照
最终标记阶段:扫描这些快照,确保被删除引用指向的对象不会被误回收
性能差异:SATB比增量更新效率更高,因为它不需要在重新标记阶段重新扫描整个对象图
三、回收流程对比类
Q5:CMS和G1的回收流程有什么本质区别?
A:
维度
CMS
G1
回收类型
只有老年代CMS GC 和Full GC
三种回收类型: 1. Young GC(只回收年轻代Region) 2. Mixed GC(回收年轻代+部分老年代Region) 3. Full GC(全堆回收,应尽量避免)
核心流程
7个阶段(4个STW+3个并发)
4个核心阶段(2个STW+2个并发): 1. 初始标记(STW) 2. 并发标记(并发) 3. 最终标记(STW) 4. 筛选回收(STW+并发)
回收策略
每次回收整个老年代
采用增量回收 策略,每次只回收一部分Region 根据用户指定的最大停顿时间,选择回收价值最高的Region(垃圾最多的Region)
Q6:什么是G1的Mixed GC?它和CMS的老年代GC有什么不同?
A:
Mixed GC定义 :G1特有的回收模式,当老年代占用率达到阈值(默认45%)时触发,同时回收所有年轻代Region 和部分老年代Region
与CMS老年代GC的区别 :
CMS每次回收整个老年代 ,停顿时间不可控;G1每次只回收部分老年代Region,停顿时间可预测
CMS回收后产生内存碎片;G1回收时采用复制算法,不会产生碎片
CMS只能在老年代满了之后触发;G1可以根据停顿时间目标灵活调整回收的Region数量
四、性能与问题对比类
Q7:CMS和G1在停顿时间方面有什么差异?
A:
CMS :停顿时间不可预测
正常情况下停顿时间很短(几十毫秒)
但一旦发生并发模式失败,会退化为Serial Old单线程Full GC,停顿时间可能长达数秒甚至数十秒
G1 :停顿时间可预测
用户可以通过-XX:MaxGCPauseMillis参数指定最大停顿时间(默认200ms)
G1会根据历史回收数据,计算每个Region的回收耗时,选择合适数量的Region进行回收,尽量满足停顿时间目标
即使发生Full GC,JDK 10及以后的G1也支持并行Full GC,停顿时间比CMS的Serial Old短得多
Q8:CMS的"并发模式失败"和G1的"疏散失败"有什么区别?
A:
CMS并发模式失败 :
原因:并发清除阶段产生的浮动垃圾超出了老年代预留空间
后果:退化为Serial Old单线程收集器,全堆Full GC,极长STW
G1疏散失败(Evacuation Failure) :
原因:回收Region时,没有足够的空Region来存放存活对象
后果:触发Full GC,JDK 10前是单线程,JDK 10及以后是多线程并行
比CMS的并发模式失败后果轻得多,且更容易通过调优避免
Q9:CMS和G1在处理大对象方面有什么不同?
A:
CMS :大对象直接分配在老年代
问题:容易触发提前Full GC,且内存碎片会导致大对象分配失败
G1 :专门设计了Humongous Region(大对象区)
大小超过Region一半的对象被视为大对象,直接分配在连续的Humongous Region中
优点:大对象不会进入年轻代,避免了频繁复制;回收时可以单独回收Humongous Region,效率更高
五、适用场景与调优对比类
Q10:CMS和G1分别适用于什么场景?
A:
CMS适用场景 (已不推荐新项目使用):
JDK 8及以下版本
堆内存较小(<8GB)
对响应时间要求极高,能接受偶尔的长时间停顿
CPU资源充足(4核及以上)
G1适用场景 (推荐所有新项目使用):
JDK 9及以上版本
堆内存较大(8GB~64GB)
需要兼顾吞吐量和响应时间
希望有可预测的停顿时间
大对象较多的应用
Q11:CMS和G1最核心的调优参数分别是什么?
A:
CMS核心调优参数 :
-XX:CMSInitiatingOccupancyFraction:老年代触发GC的阈值
-XX:+UseCMSCompactAtFullCollection:Full GC时进行内存压缩
-XX:ConcGCThreads:并发GC线程数
G1核心调优参数 :
-XX:MaxGCPauseMillis:最大停顿时间目标(最重要)
-XX:G1HeapRegionSize:设置每个Region的大小(1MB~32MB,必须是2的幂)
-XX:InitiatingHeapOccupancyPercent:触发并发标记的堆占用阈值(默认45%)
六、总结对比表(面试速记)
对比维度
CMS
G1
内存布局
传统分代(连续空间)
Region化(独立小块)
作用范围
仅老年代
全堆(年轻代+老年代)
核心算法
标记-清除
标记-整理+复制
并发标记方案
增量更新
原始快照(SATB)
停顿时间
不可预测,有长停顿风险
可预测,用户可指定
内存碎片
严重
无
大对象处理
直接分配到老年代
Humongous Region专门处理
最坏情况
退化为Serial Old单线程Full GC
并行Full GC(JDK10+)
适用堆大小
<8GB
8GB~64GB
推荐程度
已废弃,不推荐新项目
推荐所有新项目