JVM之垃圾回收面试总结

文章目录

  • 1.GC概述
    • 1.1 什么是垃圾
    • 1.2 为什么需要GC?
    • 1.3 早期垃圾回收
    • 1.4 Java垃圾回收机制
    • 1.5 评估GC的性能指标
  • 2.垃圾回收相关算法
    • 2.1 垃圾标记阶段的算法
      • 2.1.1 引用计数算法(Java没有使用)
      • 2.1.2 可达性分析算法
    • 2.2 垃圾清除阶段的算法
      • 2.2.1 标记-清除(Mark-Sweep)算法
      • 2.2.2 复制(Copying)算法
      • 2.2.3 标记-压缩(标记-整理Mark-Compact)算法
    • 2.3 分代收集算法
  • 3.垃圾回收相关概念
    • 3.1 System.gc()的理解
    • 3.2 内存溢出(OOM)
    • 3.3 内存泄漏
    • 3.4 Stop The Word(STW)
    • 3.5 垃圾回收的并发与并行
  • 4.强引用、软引用、弱引用和虚引用
  • 5.垃圾回收器
    • 5.1 Serial和Serial Old垃圾收集器:串行回收
      • 5.1.1 Serial垃圾收集器
      • 5.1.2 Serial Old垃圾收集器
    • 5.2 ParNew回收器:并行回收
    • 5.3 Parallel Scavenge回收器、Parallel Old:吞吐量优先
      • 5.3.1 Parallel Scavenge回收器
      • 5.3.2 Parallel Old回收器
      • 5.3.3 jdk8默认使用的是ParallelGC(并行垃圾回收器),也就是Parallel Scavenge + Serial Old的组合。
    • 5.4 CMS回收器:低延迟
    • 5.5 G1回收器

1.GC概述

1.1 什么是垃圾

(1)垃圾是指在运行程序中没有任何指针指向的对象
(2)如果不及时对内存中的垃圾进行清理,这些垃圾对象所占的内存空间就会一直保留到应用程序结束,被保留的空间无法被其他对象使用,甚至可能导致内存溢出

1.2 为什么需要GC?

(1)不进行垃圾回收,内存迟早会被消耗完
(2)垃圾回收也可以清除内存里的记录碎片,碎片整理将所占用的堆内存移到堆的一端,以便JVM将整理出的内存分配给新的对象

1.3 早期垃圾回收

在早期的C/C++时代,垃圾回收基本上是手工进行的,开发人员可以使用new关键字进行内存申请,并使用delete关键字进行内存释放。这种方式可以灵活控制内存释放的时间,但是会给开发人员带来频繁申请和释放内存的管理负担。如果程序员编码时忘记回收则会造成内存泄漏,严重会造成程序崩溃。

1.4 Java垃圾回收机制

(1)Java采用的是自动内存管理,无需开发人员参与内存的分配和回收,这样可以降低内存泄漏和内存溢出的风险。
(2)自动回收会弱化Java开发人员在程序出现内存溢出时的定位问题和解决问题的能力
(3)当出现内存泄漏、内存溢出问题时,我们需要实施必要的监控和调节

1.5 评估GC的性能指标

(1)吞吐量:运行用户代码的时间占总运行时间的比例(总运行时间=程序的运行时间+内存回收的时间)
(2)暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间

2.垃圾回收相关算法

2.1 垃圾标记阶段的算法

(1)在堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为已经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。
(2)当一个对象已经不再被任何的存活对象继续引用时,JVM中就会标记为死亡对象。
(3)判断对象存活一般有两种方式:引用计数算法和可达性分析算法。

2.1.1 引用计数算法(Java没有使用)

(1)引用计数算法是对每一个对象保存一个整型的引用计数器属性,用于记录对象被引用的情况。
(2)对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收了。
(3)优点:实现简单,垃圾对象便于辨识;判定效率高,且回收没有延迟性。
(4)缺点:
①它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
②每次赋值都需要重新计数,伴随着加法和减法操作,增加了时间开销。
③引用计数器无法处理循环引用。这是致命缺陷,导致在Java的垃圾回收器中没有使用这类算法。
(4)python使用了引用计数算法,它是如何解决循环引用的?
①手动解除:在合适的时机,解除引用关系
②使用弱引用weakref,weakref是python提供的标准库,旨在解决循环引用。

2.1.2 可达性分析算法

(1)可达性分析算法也叫,根搜索算法、追踪性垃圾收集。不仅实现简单、执行高效,而且可以解决循环引用问题
(2)可达性分析的基本思路
①可达性分析算法是以根对象集合(GC Roots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达(所谓GC Roots是一组必须活跃的引用)
②使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索所走过的路径称为引用链
③如果目标对象没有任何引用链相连,则是不可达的,就意味着该对象已经死亡,可以标记为垃圾对象
④在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象
(4)在Java语言中,GC Roots包括以下几类元素:
①虚拟机栈在引用的对象:比如各个线程被调用的方法中使用到的参数、局部变量等。
②本地方法栈内(通常说的本地方法)引用的对象
③方法区中类静态属性引用的对象,比如:Java类的引用类型静态变量
④方法区中常量引用的对象:比如字符串常量池(String Table)里的引用
⑤所有被同步锁synchronized持有的对象
⑥Java虚拟机内部的引用:基本数据类型对应的Class对象,一些常驻的异常对象(如:NullPointerException、OutOfMemoryError)以及系统类加载器
(5)除了这些固定的GC Roots集合意外,根据用户所选用的垃圾收集器以及当前回收的内存区域不同,还可以有其他对象“临时性”的加入,共同构成完整GC Roots集合。比如:分代收集和局部回收(Partical GC)

2.2 垃圾清除阶段的算法

(1)当成功区分出内存中存活对象和死亡对象后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的内存空间,以便有足够的可用内存空间为新对象分配内存
(2)目前在JVM中比较常见的垃圾收集算法有:标记-清除算法、复制算法、标记-压缩算法

2.2.1 标记-清除(Mark-Sweep)算法

(1)执行过程:当堆中的有效内存空间被耗尽的时候,就会停止整个程序,然后进行两项工作,第一项是标记,第二项则是清除
①标记:Collector从根节点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。
②清除:Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象的Header中没有标记为可达对象,则将其回收。
(2)优点:简单容易理解
(3)缺点:
①效率不高(从根节点标记,递归遍历可达对象,复杂度O(n),清除阶段需要把堆空间的对象遍历一遍,O(n))
②在进行GC的时候,需要停止整个应用程序,导致用户体验差
③这种方式清理出来的空闲内存是不连续的,产生内存碎片。需要维护一个空闲列表
(3)何为清除?
这里所谓的清除并不是真的置空,而是把需要清除的对象地址保存在空闲的地址列表里。下次有新对象需要加载时,判断垃圾的位置空间是否够,如果够,就直接覆盖原有位置。

2.2.2 复制(Copying)算法

(1)为了解决标记-清除算法在垃圾收集效率方面的缺陷,引入了复制算法
(2)核心思想:将活着的内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收。
在这里插入图片描述
(3)优点:
①没有标记和清除过程,实现简单,运行高效
②复制过去以后保证空间的连续性,不会出现“碎片”问题
(4)缺点:
①需要两倍的内存空间
②对于G1垃圾收集器这种拆成大量r egion的GC,复制而不是移动,意味着GC需要维护region之间对象引用关系,不管是内存占用或者时间开销也不小
(5)复制算法需要复制的存活对象数量不太多的情况。在新生代,对常规应用的垃圾回收,一次通常可以回收70%-99%的内存空间。回收性价比很高。所以现在的商业虚拟机都是用这种收集算法回收新生代。

2.2.3 标记-压缩(标记-整理Mark-Compact)算法

(1)标记-压缩算法的最终效果等同于标记-清除算法执行完成后,再进行一次碎片整理。因此,也可以把它称为标记-清除-压缩算法。
(2)执行过程
①第一阶段和标记-清除算法一样,从根节点开始标记所有被引用对象
②第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间
(3)优点:
①清除了标记-清除算法中,内存区域分散的缺点,我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可。
②消除了复制算法当中,内存减半的高额代价
(4)缺点:
①从效率上说,标记-整理算法要低于复制算法
②移动对象的同时,如果对象被其他对象引用,则还需要调整引用的地址
③移动过程中,需要全程暂停用户应用程序。

2.3 分代收集算法

(1)分代收集算法是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点使用不同的回收算法,以提高垃圾回收的效率。
(2)目前几乎所有的GC都是采用分代收集算法执行垃圾回收的。在HotSpot( SUN的JDK版本从1.3.1开始运用HotSpot虚拟机)中,基于分代的概念,GC所使用的内存回收算法必须结合年轻代和老年代各自的特点:
①年轻代:区域相对老年代较小,对象生命周期短、存活率低,回收频繁。这种情况复制算法是最快的。
②老年代:区域较大,对象生命周期长、存活率高。一般是标记-清除或者是标记-清除与标记-整理的混合实现。

3.垃圾回收相关概念

3.1 System.gc()的理解

(1)在默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用,会显示触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。System.gc()的底层就是Runtime.getRuntime().gc()
在这里插入图片描述
(2)System.gc()只是尝试调用垃圾收集器,但是不能保证对垃圾收集器一定调用
(3)JVM实现者可以通过System.gc()调用来决定JVM的GC行为。而一般情况下,垃圾回收应该是自动进行的,无需手动触发。但在一些特殊情况下,如我们正在编写一个性能基准,我们就可以在运行之间调用System.gc()

3.2 内存溢出(OOM)

(1)javadoc中对OutOfMemoryError的解释是:没有空闲内存,并且垃圾收集器也无法提供更多内存。
(2)没有空闲内存,说明Java虚拟机的堆内存不够,原因有二:
①Java虚拟机的堆内存设置不够。比如说:可能存在内存泄漏问题;也有可能就是堆的大小不合理,比如我们要处理比较可观的数据量,但是没有显式指定JVM堆大小或者指定数值偏小。我们可以通过-Xms、-Xmx来调整
②代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)。
(3)在抛出OOM之前,通常垃圾收集器会被触发,尽其所能去清理出空间。例如:在引用机制分析中,涉及到JVM会去尝试回收软引用指向的对象等。当然,也不是任何情况下垃圾收集器都会被触发,比如:我们去分配一个超大数组超过堆的最大值,JVM会判断出垃圾收集并不能解决这个问题,会直接抛出OOM

3.3 内存泄漏

(1)也叫存储泄漏,指对象不会再被程序用到,但是GC又不能回收他们的情况。一旦发生内存泄漏,程序中的可用内存最终会被耗尽,出现OOM。
(2)举例
①单例模式:单例的生命周期和应用程序是一样长的,所以单例程序中,如果持有对外部对象的引用的话,那么这个外部对象是不能被回收的,则会导致内存泄漏的产生
②一些提供close的资源未关闭导致内存泄漏。数据库连接,网络连接(socket)以及IO连接必须手动close,否则是不能被回收的。

3.4 Stop The Word(STW)

(1)Stop The Word(简称STW),指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点像卡死的感觉,这个停顿称为STW。
(2)SWT是JVM在后台自动发起和自动完成的。在用户不可见的情况下,把用户正常的工作线程全部停掉。被STW中断的应用程序线程会在完成GC之后恢复,频繁中断降低用户体验感,我们要减少STW的发生。在开发中尽量不要用System.gc(),会导致SWT的发生。
(3)可达性分析算法中枚举根节点(GC Roots)会导致所以Java执行线程停顿
(4)STW事件和采用哪款GC无关,所有的GC都会有这个事件。哪怕是G1也不能完全避免Stop The Word情况发生,只能说垃圾回收器越来越优秀,回收率越高,尽可能的缩短了暂停时间。

3.5 垃圾回收的并发与并行

(1)并行:指多条垃圾收集线程并行工作,但此时用户线程仍处于等待状态
(2)串行:单线程执行。如果内存不够,则程序暂停,启动JVM垃圾收集器进行垃圾回收,回收完,再启动程序的线程。
(3)并发:指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),垃圾回收线程在执行时不会停顿用户程序的运行。用户线程在继续执行,而垃圾收集程序线程运行于另一个CPU上。

4.强引用、软引用、弱引用和虚引用

(1)强引用:是指在程序代码中普遍存在的引用赋值,即类似“Object obj = new Object()”这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。
(2)软引用:在系统将要发生内存溢出之前,将会把这些对象列入回收范围之中进行二次回收。如果这次回收后还没有足够的内存,才会抛出内存溢出异常。
(3)弱引用:被弱引用关联的对象只能生存到下一次垃圾收集之前。当垃圾收集器工作时,无论内存空间是否足够,都会回收掉被软引用关联的对象。
(4)虚引用:一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获得一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾收集器回收时收到一个系统通知。

5.垃圾回收器

(1)垃圾收集器与垃圾分代之间的关系
在这里插入图片描述
①新生代收集器:Serial、ParNew、Parallel Scavenge
②老年代收集器:Serial Old、Parallel Old、CMS
③整堆收集器:G1

5.1 Serial和Serial Old垃圾收集器:串行回收

5.1.1 Serial垃圾收集器

(1)Serial垃圾收集器是最基本、历史最悠久的垃圾收集器。JDK1.3之前回收新生代唯一的选择
(2)Serial垃圾收集器是Client模式下的默认新生代垃圾收集器
(3)Serial垃圾收集器采用复制算法、串行回收和“Stop-the-Word”的机制执行回收

5.1.2 Serial Old垃圾收集器

(1)Serial Old垃圾收集器同样也采用了串行回收和“Stop-the-Word”机制,只不过内存回收算法使用的是标记-压缩算法。
(2)Serial Old是Client模式下默认的老年代垃圾回收器
(3)Serial Old在Server模式下主要有两个用途:
①与新生代的Parallel Scavenge配合使用
②作为老年代CMS收集器的后备垃圾收集方案

5.2 ParNew回收器:并行回收

(1)ParNew收集器是Serial收集器的多线程版本。ParNew也是采用复制算法、“Stop-the-Word”机制。
(2)ParNew收集器运行在多CPU的环境下,可以充分利用多CPU、多核心等物理硬件资源的优势,更快的完成垃圾收集,提升程序的吞吐量。但是在单个CPU的环境下,ParNew收集器没有Serial收集器效率高。虽然Serial收集器是基于串行回收,但是由于CPU不需要频繁的做任务切换,因此可以有效的避免多线程交互过程中产生的一些额外开销。
(3)除了Serial外,目前只有ParNew能与CMS收集器配合工作。

5.3 Parallel Scavenge回收器、Parallel Old:吞吐量优先

5.3.1 Parallel Scavenge回收器

(1)Parallel Scavenge和ParNew一样是基于并行回收,采用复制算法、“Stop-the-Word”机制。Parallel Scavenge是吞吐量优先的垃圾收集器。
(2)自适应调节策略(在JVM运行过程中,根据当前的运行情况进行一个性能的监控,动态调整内存中的分配的情况,以达到最优策略,比如吞吐量最优)也是Parallel Scavenge和ParNew一个重要区别

5.3.2 Parallel Old回收器

Parallel Old收集器,是用来代替老年代的Serial Old收集器。Parallel Old和Serial Old一样采用标记-压缩算法和“Stop-the-Word”机制。但是是基于并行回收。

5.3.3 jdk8默认使用的是ParallelGC(并行垃圾回收器),也就是Parallel Scavenge + Serial Old的组合。

5.4 CMS回收器:低延迟

(1)CMS即Concurrent-Mark-Sweep收集器,实现了让垃圾收集线程与用户线程同时工作
(2)CMS缩短了垃圾收集时用户线程的停顿时间,即低延迟。
(3)CMS采用 标记-清除 算法,并且也会“Stop-the-Word”

5.5 G1回收器

(1)将Parallel Scavenge和CMS两种垃圾收集器的优点融合。
①支持巨大的堆空间回收,并有较高的吞吐量
②允许用户设置最大暂停时间
(2)G1的整个堆会被划分成多个大小相等的区域,称之为区Region,区域不要求是连续的。分为Eden、Survior、Old区。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/23239.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RAG 高效应用指南 :Query 理解

前言 构建一个检索增强生成 (Retrieval-Augmented Generation, RAG) 应用的 PoC(概念验证,Proof of Concept)过程相对简单,但要将其推广到生产环境中则会面临多方面的挑战。这主要是因为 RAG 系统涉及多个不同的组件,…

Termux安装SSH服务与内网穿透工具实现远程SFTP传输文件

文章目录 前言1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 前言 本教程主要介绍如何在安卓 Termux 系统中使用 SFTP 文件传输并结合[cpolar内网穿透工具](cpolar - 安全的内网穿透工具)轻松实现无公网IP远程传输,无需购…

ATFX汇市:加拿大央行或启动首次降息,关注加元贬值风险

ATFX汇市:今日21:45,加拿大央行将公布6月份利率决议结果,当前的基准利率为5%,市场普遍预期其将降息25基点,最新基准利率有可能调降至4.75%。市场人士预期降息的主要依据有两点,其一是加拿大央行行长麦克勒姆…

超级详细Spring AI运用Ollama大模型

大模型工具Ollama 官网:https://ollama.com/ Ollama是一个用于部署和运行各种开源大模型的工具; 它能够帮助用户快速在本地运行各种大模型,极大地简化了大模型在本地运行的过程。用户通过执行几条命令就能在本地运行开源大模型,如Lama 2等; 综上&#x…

SpringBoot:SpringBoot中使用Redisson实现分布式锁

一、前言 Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。 刚好项目中需要使用到分布式锁,记录一下Redisson是如何使用分布式…

(免费领源码)Java#springboot#MySQL书法社团管理系统36200-计算机毕业设计项目选题推荐

目 录 摘要 Abstract 1 绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 书法社团管理系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析…

SqlServer2016企业版安装

前言 好久没有知识的累积,最近工作上遇到新的SqlServer2016安装,记录一下 参考文章 SQL Server 2016软件安装包和安装教程 - 哔哩哔哩 (bilibili.com) 安装包准备 需要提前准备软件安装包如下 cn_sql_server_2016_enterprise_x64_dvd_8699450&…

【文档智能】符合人类阅读顺序的文档模型-LayoutReader原理及权重开源

引言 阅读顺序检测旨在捕获人类读者能够自然理解的单词序列。现有的OCR引擎通常按照从上到下、从左到右的方式排列识别到的文本行,但这并不适用于某些文档类型,如多栏模板、表格等。LayoutReader模型使用seq2seq模型捕获文本和布局信息,用于…

如何使用 DANN 改进神经网络

文章目录 一、说明二、语言模型真的理解语言吗?三、了解分配转变3.1 样本选择偏差3.2 非静止环境3.3 领域适配挑战3.4 概念漂移 四、对领域对抗训练的介绍 一、说明 由于其多功能性,神经网络是大多数现代机器学习管道的主要内容。他们处理非结构化数据的…

【Visual Studio 2022 部署 .net core website】

部署网站 AdminPortal.csproj false Website File Nameappsettings.jsonAdminPortal.deps.jsonAdminPortal.runtimeconfig.json–web.configAPI.runtimeconfig.json

idea 中:运行 Application 时出错。命令行过长

一、问题描述: idea 导入新项目,在编译后,运行项目时,报以下错误: 14:47 运行 Application 时出错运行 Application 时出错。命令行过长。通过 JAR 清单或通过类路径文件缩短命令行,然后重新运行。二、问题…

大型语言模型智能体(LLM Agent)在实际使用的五大问题

在这篇文章中,我将讨论人们在将代理系统投入生产过程中经常遇到的五个主要问题。我将尽量保持框架中立,尽管某些问题在特定框架中更加常见。 1. 可靠性问题 可靠性是所有代理系统面临的最大问题。很多公司对代理系统的复杂任务持谨慎态度,因…

SpringBoot定时任务+Quartz 动态调度

1、分部解释 2、完整代码 3、SpringBoot定时任务Quartz 1、动态定时任务: 动态定时任务,即定时任务的动态调度,可根据需求自由的进行任务的生成、暂停、恢复、删除和更新操作。Quartz本身没有提供动态调度的功能,需要自己根据相关的API开发。…

wireshark源码分析 是怎么完成协议识别的

代码流程 通过process_packet_single_pass处理单个数据包,每层数据包都会使用decode_udp(tcp)_ports识别协议,这里面提供端口和特征识别; 端口识别:dissector_try_uint_new 在接口内通过find_uint_dtbl_entry 如果是一个HTTP数…

数据可视化之常用图表热力图

1.什么是热力图? 热力图,是一种通过对色块着色来显示数据的统计图表。 绘图时,需指定颜色映射的规则。 例如,较大的值由较深的颜色表示,较小的值由较浅的颜色表示;较大的值由偏暖的颜色表示,…

【摄影测量02】什么是内外方位参数?坐标系旋转变换?

【摄影测量02】什么是内外方位参数?坐标系旋转变换? 文章目录 【摄影测量02】什么是内外方位参数?坐标系旋转变换?引言1 内方位元素与外方位元素1.1 内方位元素1.2 外方位元素 2 旋转矩阵的概念与应用2.1 旋转矩阵的定义2.2 坐标变…

chatglm3-6b小试

原本想在VMware中装个unbutu,再搞chatglm,但经过调研发现业内都是采用双系统来搞chat的开发。于是只好用rufus制作了一个ubuntu22.04的系统盘,你需要准备8G,因为制作好镜像后是7个多G。安装这里就不说了。 1 ubuntu环境 安装好ubu…

升级HarmonyOS 4.2,开启健康生活篇章

夏日来临,华为智能手表携 HarmonyOS 4.2 版本邀您体验,它不仅可以作为时尚单品搭配夏日绚丽服饰,还能充当你的健康管家,从而更了解自己的身体,开启智能健康生活篇章。 高血糖风险评估优化,健康监测更精准 …

海南聚广众达电子商务咨询有限公司靠谱吗?

在数字经济的浪潮中,抖音电商作为新兴业态,正以其独特的魅力和强大的势能,改变着传统商业模式,引领着新一轮的消费潮流。海南聚广众达电子商务咨询有限公司,作为抖音电商服务领域的佼佼者,凭借其专业的团队…

重学java 65.IO流 缓冲流

I am not afraid tomorrow for I have seen yesterday and love today —— 24.6.5 一、字节缓冲流 1.字节缓冲流的意义 之前所写的FileOutputstream、FileInputstream、FileReader、Filewriter这都叫做基本流,其中FileInputstream和FieOutputstream的读写方法都是本地方法(方…