JVM垃圾回收器

简介

Java 垃圾回收器(Garbage Collectors)是 Java 虚拟机(JVM)中的组件,负责自动管理内存,回收无用的对象以释放内存资源。它通过检测不再被引用的对象,并将其标记为可回收状态,然后进行垃圾回收操作,将其所占用的内存释放出来。

评价标准

评估 Java 垃圾回收器的好坏通常涉及以下几个标准:

  1. 内存回收效率:好的垃圾回收器应能有效地回收无用对象,释放内存资源。它应该能够尽可能快地识别和回收大量的垃圾对象,以避免过度占用内存。
  2. 停顿时间:好的垃圾回收器应具有低停顿时间,即在进行垃圾回收时,能够最小化对应用程序的影响,减少长时间的停顿或暂停现象。较低的停顿时间可以提供更好的响应性能和用户体验。
  3. 吞吐量:好的垃圾回收器应具有高吞吐量,即在进行垃圾回收时,能够以高效率地处理垃圾对象,使得应用程序的运行时间占总时间的比例尽可能小。高吞吐量通常与高并发性和高性能相关。
  4. 可扩展性:好的垃圾回收器应具有良好的可扩展性,能够适应不同规模和负载的应用程序。它应该能够在大型应用程序和多核处理器环境下正常工作,并能够根据需求进行动态调整。
  5. 配置和调优选项:好的垃圾回收器应提供丰富的配置和调优选项,以满足不同应用程序的需求。它应该允许开发人员根据应用程序的特性和性能目标来优化垃圾回收行为,以达到最佳的性能和资源利用。

好的垃圾回收器并不是普适的,而是根据具体的应用需求和环境来评估和选择的。不同的应用程序可能对垃圾回收器的优先级和需求有所不同。因此,在选择垃圾回收器时,需要综合考虑应用程序的性质、性能要求和运行环境等因素,并进行实际的性能测试和评估。

几种垃圾回收器

常见回收器有SerialGC、Parallel Scavenge、Parallel Old、CMS GC、G1和ZGC,JDK8版本默认使用ParallelGC(Parallel Scavenge和Parallel Old),也可以切换除ZGC之外的其他,JDK9默认使用G1,JDK11后开始出现ZGC,JDK15中默认使用ZGC,因此建议着重了解ParallelGC、G1以及ZGC。

一、Serial GC

Serial GC是最基本、最古老的垃圾回收器,也是串行化执行的,即它使用单线程进行垃圾回收操作,使用标记-压缩(Mark-Compact)算法来进行垃圾回收。它按照以下步骤执行:

  1. 标记阶段:从根对象开始,递归遍历对象图,标记所有被引用的对象为活动对象(reachable objects),将未标记的对象视为垃圾对象(garbage objects)。
  2. 压缩阶段:将活动对象压缩到内存的一端,紧凑排列,以消除内存碎片化。这样,垃圾对象所占用的内存空间就会被释放出来,可以重新利用。
  3. 清除阶段:清除未标记的垃圾对象,释放它们的内存空间。

配置和调优选项

配置项

ruby 复制代码
-XX:+UseSerialGC:启用 Serial GC。
-XX:NewRatio=<value>:设置新生代和老年代的比值。
-XX:SurvivorRatio=<value>:设置 Eden 区域和 Survivor 区域的比值。
-Xms<size>:设置初始堆大小。
-Xmx<size>:设置最大堆大小。

调优项

ruby 复制代码
调整堆大小:根据应用程序的需求和系统资源的情况,适当调整初始堆大小(-Xms)和最大堆大小(-Xmx)。过小的堆可能导致频繁的垃圾回收,而过大的堆可能导致较长的垃圾回收时间。
调整新生代和老年代比例:使用 -XX:NewRatio 参数可以调整新生代和老年代的比例。增大新生代的比例可能会导致更频繁的垃圾回收,但每次回收的对象数量较小。相反,减小新生代的比例可能会减少垃圾回收的频率,但每次回收的对象数量较大。

特点

  1. 单线程执行:Serial GC 是单线程的垃圾回收器,它在进行垃圾回收时会暂停应用程序的执行。这意味着在进行垃圾回收期间,应用程序的所有线程都会停止执行。
  2. 简单高效:由于 Serial GC 是单线程的,它的实现相对简单,没有复杂的并发控制和线程同步的开销。这使得它在小型应用程序或单线程环境中表现出较好的性能。
  3. 低内存占用:Serial GC 在进行垃圾回收时,只使用一个线程,占用较少的系统资源和内存。这使得它在资源受限的环境下比较适用。

适用场景

  1. 小型应用程序:对于小型的应用程序,Serial GC 可能是一个不错的选择,因为它的实现简单且占用较少的内存资源。
  2. 单线程环境:如果应用程序是单线程的,没有并发要求,那么使用 Serial GC 可能是合适的。
  3. 资源受限环境:在资源受限的环境下,如嵌入式设备或移动设备,Serial GC 的低内存占用和简单性可能是优势。

由于 Serial GC 使用单线程进行垃圾回收,它的停顿时间可能较长,可能会对大型应用程序或需要高并发性能的应用程序产生较大的影响。

二、Parallel Scavenge

Parallel Scavenge主要用于实现低延迟的年轻代多线程并行垃圾回收器,适用于对吞吐量要求较高的应用程序,使用复制算法来进行垃圾回收。它按照以下步骤执行:

  1. 新生代划分:Parallel Scavenge 将新生代划分为两个相同大小的区域,一个是 Eden 区域,一个是 Survivor 区域。通常,Eden 区域占新生代的80%,Survivor 区域占新生代的10%。另外的10%用于存储被引用的对象。
  2. 复制阶段:在复制阶段,当 Eden 区域满时,Parallel Scavenge 将 Eden 区域和 Survivor 区域中的存活对象复制到另一个空闲的 Survivor 区域中。如果 Survivor 区域也满了,那么存活的对象会被复制到老年代。
  3. 晋升阶段:当对象在 Survivor 区域中经历了多次复制后,它将晋升到老年代。这个阶段的触发条件是根据晋升的对象年龄(Age)来确定的。
  4. 并行执行:Parallel Scavenge 使用多个线程并行执行垃圾回收操作,包括对象复制和晋升操作。这样可以充分利用多核处理器的优势,提高垃圾回收的吞吐量。

配置和调优项

配置

ruby 复制代码
-XX:+UseParallelGC:启用 Parallel Scavenge。
-XX:ParallelGCThreads=<value>:设置用于垃圾回收的线程数。默认值为 CPU 核心数。
-XX:MaxGCPauseMillis=<value>:设置垃圾回收的最大停顿时间目标(毫秒)。
-Xms<size>:设置初始堆大小。
-Xmx<size>:设置最大堆大小。

调优

ruby 复制代码
调整堆大小:根据应用程序的需求和系统资源的情况,适当调整初始堆大小(-Xms)和最大堆大小(-Xmx)。过小的堆可能导致频繁的垃圾回收,而过大的堆可能导致较长的垃圾回收时间。

调整并行线程数:使用 -XX:ParallelGCThreads 参数可以调整用于垃圾回收的线程数。增加线程数可以提高垃圾回收的吞吐量,但也会增加与垃圾回收相关的系统负载。

设置最大停顿时间目标:使用 -XX:MaxGCPauseMillis 参数可以设置垃圾回收的最大停顿时间目标。根据应用程序对延迟的要求,可以适当调整该值,以平衡吞吐量和停顿时间。

特点

  1. 并行执行:Parallel Scavenge 使用多个线程并行执行垃圾回收操作,以提高吞吐量。它适用于那些追求高吞吐量和处理能力的应用程序。
  2. 低延迟:由于并行执行,Parallel Scavenge 通常可以提供较低的停顿时间。它的设计目标是减少长时间的停顿,提供更好的响应性能。
  3. 自适应调节:Parallel Scavenge 具有自适应调节的能力,它可以根据系统负载和垃圾回收的效果来动态调整相关参数,以达到更好的性能。

适用场景

  1. 吞吐量要求较高的应用程序:如果应用程序的主要目标是提高吞吐量和处理能力,而对停顿时间的要求相对较低,那么使用 Parallel Scavenge 可以获得较好的性能。
  2. 数据处理和批量任务:Parallel Scavenge 适用于那些需要处理大量数据和执行批量任务的应用程序,可以充分利用多核处理器的优势,提供高吞吐量。

由于 Parallel Scavenge 主要关注吞吐量和处理能力,它可能会导致较长的停顿时间。对于对停顿时间要求较高的应用程序,可以考虑使用其他并发的垃圾回收器

三、Parallel Old

Parallel Old工作于对老年代,对老年代对象进行并行回收。它与 Parallel Scavenge 垃圾回收器配合使用,共同完成整个堆的垃圾回收。使用标记-整理(Mark-Compact)算法来进行垃圾回收。它按照以下步骤执行:

  1. 初始标记阶段:在初始标记阶段,Parallel Old 会暂停应用程序的执行,标记根对象及其直接引用的对象为活动对象(reachable objects)。这个过程是短暂的,通常只需要几毫秒。
  2. 并发标记阶段:在并发标记阶段,Parallel Old 在一个或多个辅助线程的帮助下,并发地遍历对象图,标记所有被引用的对象为活动对象。与此同时,应用程序的线程可以继续执行。这个阶段的并发执行可以减少停顿时间。
  3. 重新标记阶段:在重新标记阶段,Parallel Old 会再次暂停应用程序的执行,标记在并发标记阶段发生变化的对象。这个过程通常比初始标记阶段更短暂。
  4. 整理阶段:在整理阶段,Parallel Old 对存活的对象进行整理,将它们向堆的一端移动,以便在堆的另一端创建更大的连续空闲空间。这样可以减少内存碎片化,提高内存利用率。

配置和调优项

配置

ruby 复制代码
-XX:+UseParallelOldGC:启用 Parallel Old。
-XX:ParallelGCThreads=<value>:设置用于垃圾回收的线程数。默认值为 CPU 核心数。
-Xms<size>:设置初始堆大小。
-Xmx<size>:设置最大堆大小。

调优

ruby 复制代码
调整堆大小:根据应用程序的需求和系统资源的情况,适当调整初始堆大小(-Xms)和最大堆大小(-Xmx)。过小的堆可能导致频繁的垃圾回收,而过大的堆可能导致较长的垃圾回收时间。

调整并行线程数:使用 -XX:ParallelGCThreads 参数可以调整用于垃圾回收的线程数。增加线程数可以提高垃圾回收的吞吐量,但也会增加与垃圾回收相关的系统负载。

调整新生代和老年代比例:Parallel Old 与 Parallel Scavenge 结合使用,可以通过调整 Parallel Scavenge 的新生代和老年代比例来影响 Parallel Old 的性能。使用 -XX:ParallelGCThreads 参数可以调整新生代和老年代的比例。

特点

  1. 并行执行:Parallel Old 使用多个线程并行执行垃圾回收操作,以提高吞吐量。它与 Parallel Scavenge 垃圾回收器配合使用,共同完成整个堆的垃圾回收。
  2. 低停顿时间:由于并发执行,Parallel Old 的停顿时间相对较低。它的目标是减少长时间的停顿,提供较好的用户体验。
  3. 吞吐量折衷:为了减少停顿时间,Parallel Old 可能会牺牲一些吞吐量。它的设计目标是在提供合理的吞吐量的同时,尽量减少垃圾回收导致的停顿。

适用场景

  1. 吞吐量要求较高的应用程序:如果应用程序的主要目标是提高吞吐量和处理能力,而对停顿时间的要求相对较低,那么使用 Parallel Old 可以获得较好的性能。
  2. 对老年代的垃圾回收需求:Parallel Old 主要用于对老年代进行垃圾回收,适用于那些老年代对象相对较多的应用程序。

Parallel Old 在进行垃圾回收时会占用一些系统资源,如辅助线程和内存开销等。此外,由于并行执行,它可能导致应用程序的吞吐量稍有降低。

四、CMS GC

CMS GC作用于老年代,旨在减少垃圾回收造成的停顿时间,以提供更好的响应性能,使用标记-清除(Mark-Sweep)算法来进行垃圾回收。它按照以下步骤执行:

  1. 初始标记阶段:在初始标记阶段,CMS GC 会暂停应用程序的执行,标记根对象及其直接引用的对象为活动对象(reachable objects)。这个过程是短暂的,通常只需要几毫秒。
  2. 并发标记阶段:在并发标记阶段,CMS GC 在一个或多个辅助线程的帮助下,并发地遍历对象图,标记所有被引用的对象为活动对象。与此同时,应用程序的线程可以继续执行。这个阶段的并发执行可以减少停顿时间。
  3. 重新标记阶段:在重新标记阶段,CMS GC 会再次暂停应用程序的执行,标记在并发标记阶段发生变化的对象。这个过程通常比初始标记阶段更短暂。
  4. 清除阶段:在清除阶段,CMS GC 清除未标记的垃圾对象,释放它们的内存空间。这个阶段与应用程序的执行并发进行。

配置和调优项

配置

diff 复制代码
-XX:+UseConcMarkSweepGC:启用 CMS GC。
-Xms<size>:设置初始堆大小。
-Xmx<size>:设置最大堆大小。

调优

ruby 复制代码
调整堆大小:根据应用程序的需求和系统资源的情况,适当调整初始堆大小(-Xms)和最大堆大小(-Xmx)。过小的堆可能导致频繁的垃圾回收,而过大的堆可能导致较长的垃圾回收时间。

设置并发线程数:使用 -XX:ParallelCMSThreads 参数可以设置用于并发标记阶段的线程数。增加线程数可以加快并发标记的速度,但也会增加与垃圾回收相关的系统负载。

调整 CMS 相关的参数:以下是一些与 CMS GC 相关的参数,可以根据应用程序的需求进行调整:
    -XX:CMSInitiatingOccupancyFraction=<value>:设置触发并发标记周期的老年代占用率阈值。
    -XX:+UseCMSInitiatingOccupancyOnly:仅使用 CMSInitiatingOccupancyFraction 触发并发标记周期。
    -XX:+CMSParallelRemarkEnabled:启用并发标记后的并行重标记阶段,用于减少停顿时间。

特点

  1. 并发执行:CMS GC 的标记和清除阶段是与应用程序并发执行的,这意味着它在进行垃圾回收时可以与应用程序的执行同时进行。这可以减少停顿时间,提供更好的响应性能。
  2. 低停顿时间:由于并发执行,CMS GC 的停顿时间相对较低。它的目标是减少长时间的停顿,以提供较好的用户体验。
  3. 吞吐量折衷:为了减少停顿时间,CMS GC 采取了一些折衷措施。相比于 Parallel GC,它可能会降低一些吞吐量,但可以提供更低的停顿时间。

适用场景

  1. 响应性要求较高的应用程序:如果应用程序对停顿时间有较高的要求,需要提供更好的响应性能,那么使用 CMS GC 可能是一个不错的选择。
  2. 多核处理器环境:CMS GC 可以与应用程序并发执行,与 Parallel GC 类似,它也可以充分利用多核处理器的优势,提供较好的性能。

由于CMS GC 在进行垃圾回收时会占用一些系统资源,如辅助线程和内存开销等。此外,由于并发执行,它可能导致应用程序的吞吐量稍有降低。

五、G1

G1(Garbage-First)是一种基于区域(Region)划分的垃圾回收器,旨在提供较低的停顿时间和高吞吐量,G1 垃圾回收器与传统的分代式垃圾回收器不同,它使用了一种基于区域划分的方式来管理整个堆空间。它按照以下步骤执行:

  1. 区域划分:G1 将整个堆空间划分为多个大小相等的区域(Region),每个区域可以是 Eden 区域、Survivor 区域或老年代区域。这种区域划分的方式消除了传统分代式垃圾回收器中由于代之间的对象引用关系而导致的一些限制。
  2. 初始标记阶段:在初始标记阶段,G1 会标记根对象及其直接引用的对象为活动对象,这个过程会导致一小段的暂停时间。
  3. 并发标记阶段:在并发标记阶段,G1 在一个或多个辅助线程的帮助下,并发地遍历对象图,标记所有被引用的对象为活动对象。与此同时,应用程序的线程可以继续执行。
  4. 最终标记阶段:在最终标记阶段,G1 会暂停应用程序的执行,完成并发标记阶段期间有变化的对象的标记。这个过程的停顿时间通常比初始标记阶段稍长。
  5. 整理阶段:在整理阶段,G1 将活动对象从不同的区域复制到一个或多个空闲的区域中,以便在堆的一端创建更大的连续空闲空间。这样可以减少内存碎片化,提高内存利用率。

配置和调优项

配置

diff 复制代码
-XX:+UseG1GC:启用 G1 GC。
-Xms<size>:设置初始堆大小。
-Xmx<size>:设置最大堆大小。

调优

ruby 复制代码
1.调整堆大小:根据应用程序的需求和系统资源的情况,适当调整初始堆大小(-Xms)和最大堆大小(-Xmx)。过小的堆可能导致频繁的垃圾回收,而过大的堆可能导致较长的垃圾回收时间。

2.设置并发线程数:使用 -XX:ConcGCThreads 参数可以设置用于并发标记和并发清理的线程数。增加线程数可以加快并发阶段的速度,但也会增加与垃圾回收相关的系统负载。

3.调整 G1 相关的参数:以下是一些与 G1 GC 相关的参数,可以根据应用程序的需求进行调整:
	-XX:G1HeapRegionSize=<value>:设置 G1 堆区域的大小,影响垃圾回收的粒度。
	-XX:MaxGCPauseMillis=<value>:设置垃圾回收的最大停顿时间目标(毫秒)。
	-XX:InitiatingHeapOccupancyPercent=<value>:设置触发混合收集周期的堆占用率阈值。
4.调整并发收集阶段的时间比例:使用 -XX:G1MixedGCLiveThresholdPercent 和 -XX:G1MixedGCCountTarget 参数可以调整并发收集阶段的时间比例,以平衡吞吐量和停顿时间。

5.监控和分析 G1 GC 行为:使用 JVM 提供的 GC 日志和相关工具,如 GCViewer、G1GCLogAnalyzer 等,可以对 G1 GC 的行为进行监控和分析,以识别潜在的性能瓶颈和调优机会。

特点

  1. 低停顿时间:G1 的设计目标之一是提供较低的停顿时间。它通过并发标记和并发整理等技术手段,在垃圾回收过程中减少长时间的停顿,提高应用程序的响应性能。
  2. 可预测的停顿时间:G1 通过将堆空间划分为多个区域,并根据每个区域的垃圾回收情况来动态选择回收的区域,从而实现可预测的停顿时间。它可以根据应用程序的需求和系统资源的情况,灵活地调整垃圾回收的策略。
  3. 增量回收:G1 支持增量回收,将整个垃圾回收过程划分为多个小步骤,每个步骤之间插入短暂的并发执行时间。这样可以进一步降低停顿时间,减少对应用程序的影响。

由于G1 在垃圾回收过程中会占用一些系统资源,如辅助线程和内存开销等。它的性能与具体的应用程序、堆空间大小和系统配置等因素有关。在选择垃圾回收器时,需要综合考虑应用程序的性能需求、停顿时间要求和系统资源的可用性等因素。

适用场景

  1. 大堆应用程序:G1 的区域划分方式可以更好地管理大堆空间,减少停顿时间。它适用于那些需要管理几十GB到几百GB堆空间的应用程序。
  2. 低停顿时间要求:如果应用程序对停顿时间有较低的要求,并且可以接受一定程度的吞吐量损失,那么使用 G1 可以获得较好的性能。
  3. 频繁的全局垃圾回收:G1 的增量回收和可预测的停顿时间特性使其适用于需要频繁进行全局垃圾回收的应用程序。

六、ZGC

ZGC(Z Garbage Collector)是一种并发的、低停顿时间的垃圾回收器,旨在提供非常短的停顿时间,使得大型堆和需要低延迟的应用程序能够更好地运行,它采用了一种全新的垃圾回收方式,与传统的基于分代的回收器不同。它按照以下步骤执行:

  1. 并发标记阶段:在并发标记阶段,ZGC 在后台线程的帮助下,并发地遍历对象图,并标记所有活动对象。与此同时,应用程序的线程可以继续执行,无需停顿。
  2. 并发清理阶段:在并发清理阶段,ZGC 在后台线程的帮助下,并发地清理未被标记为活动对象的垃圾。这个过程也是在应用程序执行的同时进行的。
  3. 并发整理阶段:在并发整理阶段,ZGC 会将活动对象从堆的一部分移动到另一部分,以便在堆的一端创建更大的连续空闲空间。这个过程也是在应用程序执行的同时进行的。
  4. 短暂的停顿阶段:在完成一定量的并发工作后,ZGC 需要进行短暂的停顿来更新内部数据结构和处理特殊情况。这个停顿的时间通常非常短,通常在毫秒级别。

配置和调优项

配置

diff 复制代码
-XX:+UseZGC:启用 ZGC。
-Xms<size>:设置初始堆大小。
-Xmx<size>:设置最大堆大小。

调优

ruby 复制代码
1.调整堆大小:根据应用程序的需求和系统资源的情况,适当调整初始堆大小(-Xms)和最大堆大小(-Xmx)。过小的堆可能导致频繁的垃圾回收,而过大的堆可能导致较长的垃圾回收时间。

2.设置并发线程数:使用 -XX:ConcGCThreads 参数可以设置用于并发标记和并发清理的线程数。增加线程数可以加快并发阶段的速度,但也会增加与垃圾回收相关的系统负载。

3.调整 ZGC 相关的参数:以下是一些与 ZGC 相关的参数,可以根据应用程序的需求进行调整:
	-XX:ConcGCThreads:设置并发垃圾回收的线程数。可以根据系统的 CPU 核心数和应用程序的需求进行调整,默认值是处理器核心数的 1/4。
	-XX:ConcGCThreadsForeground:设置在前台执行并发垃圾回收的线程数。默认情况下,这个值与 -XX:ConcGCThreads 相同。如果你的应用程序在并发垃圾回收期间需要更多的 CPU 资源,可以适当增加这个值。
	-XX:ParallelGCThreads:设置并行垃圾回收的线程数。ZGC 在并行阶段使用这些线程进行垃圾回收操作,默认值是处理器核心数的 1/4。
	-XX:MaxGCPauseMillis:设置期望的最大停顿时间(毫秒)。ZGC 会尽量控制停顿时间在这个范围内。可以根据应用程序对延迟的要求进行调整。
	-XX:ZUncommitDelay:设置未使用区域的延迟释放时间(毫秒)。默认情况下,当 ZGC 发现某个区域完全未使用时,会将其释放回系统,以节省内存。这个参数可以用来设置延迟释放的时间,以减少频繁的内存释放和分配。
	-XX:SoftMaxHeapSize:设置软限制的最大堆大小。ZGC 会尝试在这个限制内进行垃圾回收。如果超过这个限制,ZGC 会尽量减少停顿时间,但可能会导致更频繁的垃圾回收。
4.监控和分析 ZGC 行为:使用 JVM 提供的 GC 日志和相关工具,如 GCViewer、ZGCLogAnalyzer 等,可以对 ZGC 的行为进行监控和分析,以识别潜在的性能瓶颈和调优机会。

特点

  1. 极低的停顿时间:ZGC 的设计目标之一是提供非常短的停顿时间,通常在毫秒级别。它通过并发执行垃圾回收的各个阶段,以及短暂的停顿阶段来实现这一目标,从而保证应用程序的低延迟性能。
  2. 并发执行:ZGC 在整个垃圾回收过程中,包括标记、清理和整理阶段,都与应用程序的执行并发进行。这意味着应用程序的线程可以继续执行,无需长时间的停顿。
  3. 可控的延迟:ZGC 提供了一些参数和选项,可用于控制垃圾回收的延迟。开发人员可以根据应用程序的需求和性能目标来调整这些参数,以达到最佳的延迟和吞吐量的平衡。
  4. 大堆支持:ZGC 特别适用于大堆场景,可以管理数十GB甚至数百GB的堆空间。

适用场景

  1. 低延迟要求:如果应用程序对停顿时间有极低的要求,需要保持非常短的停顿时间,那么使用 ZGC 可以获得出色的性能。
  2. 大堆应用程序:ZGC 的并发执行和低延迟特性使其非常适合管理大堆空间,如需要数十GB到数百GB的堆空间。
  3. 低延迟的垃圾回收需求:如果应用程序需要频繁进行垃圾回收,并且需要非常短的停顿时间来保证低延迟性能,那么 ZGC 是一个很好的选择。

由于ZGC 的并发执行和低停顿时间的特性需要一定的系统资源支持。它对 CPU 和内存的需求相对较高,因此在选择 ZGC 作为垃圾回收器时,需要综合考虑应用程序的性能需求、停顿时间要求和系统资源的可用性等因素。

相关推荐
程序员是干活的3 分钟前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节
煸橙干儿~~13 分钟前
分析JS Crash(进程崩溃)
java·前端·javascript
2401_8543910814 分钟前
Spring Boot大学生就业招聘系统的开发与部署
java·spring boot·后端
Amor风信子15 分钟前
华为OD机试真题---跳房子II
java·数据结构·算法
杨荧41 分钟前
【JAVA开源】基于Vue和SpringBoot的洗衣店订单管理系统
java·开发语言·vue.js·spring boot·spring cloud·开源
陈逸轩*^_^*1 小时前
Java 网络编程基础
java·网络·计算机网络
这孩子叫逆1 小时前
Spring Boot项目的创建与使用
java·spring boot·后端
星星法术嗲人1 小时前
【Java】—— 集合框架:Collections工具类的使用
java·开发语言
一丝晨光2 小时前
C++、Ruby和JavaScript
java·开发语言·javascript·c++·python·c·ruby
天上掉下来个程小白2 小时前
Stream流的中间方法
java·开发语言·windows