JVM之垃圾回收面试总结

news2024/12/25 15:07:13

文章目录

  • 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.coloradmin.cn/o/1793637.html

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

相关文章

C语言 | Leetcode C语言题解之第128题最长连续序列

题目&#xff1a; 题解&#xff1a; typedef struct {int key;UT_hash_handle hh; }Hash; int longestConsecutive(int* nums, int numsSize) {Hash* headNULL;Hash* tempNULL;for(int i0;i<numsSize;i){int numnums[i];HASH_FIND_INT(head,&num,temp);if(!temp){temp…

Java编程常见问题汇总六

系列文章目录 文章目录 系列文章目录前言一、反射使用不当二、不必要的同步三、错误的选择List类型四、HashMap size陷阱五、对Hashtable, HashMap 和 HashSet了解不够 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不…

Ruoyi-Blog 基于若依后台的博客系统,长期维护

RuoYiBlog-一个基于若依的超级漂亮的博客系统 ✨项目介绍 一直想做一个博客平台&#xff0c;看过许多优秀的开源项目&#xff0c;但没有找到合适的。于是我利用业余时间把若依后台管理和pb-cms结合起来&#xff0c;在自己的参考中开发了一部分&#xff0c;就有了这个 项目可用…

【数学建模】MATLAB入门教程:插值与拟合(下)

前言 插值与拟合在数据处理和科学计算中扮演着非常重要的角色&#xff0c;它们用于估算未知数据点的值&#xff0c;帮助我们理解和预测数据趋势 一、一维插值 1、一维插值定义 已知n1个节点(,)(j0,1,...,n,其中互不相同&#xff0c;不妨设a<<...<b),求任一插值点(…

CSAPP Lab06——Shell Lab通关思路

远距离的欣赏 近距离的迷惘 谁说太阳会找到月亮 ——修炼爱情 完整代码见&#xff1a;CSAPP/shlab-handout at main SnowLegend-star/CSAPP (github.com) 上来就遇到了些小问题&#xff1a;①本来想看看“tshref”支持的命令&#xff0c;结果命令居然被拒绝执行了&#xff0c;…

现代密码学-认证协议

A.B两个用户想通过网络先建立安全的共享密钥再进行保密通信&#xff1f;A(B)如何确信自己正在和B(A)通信而不是C&#xff1f;这种通信方式为双向通信&#xff0c;此时的认证为相互认证。 相互认证 A/B两个用户在建立共享密钥时需要考虑的核心问题&#xff1a;保密性和实时性&…

刷代码随想录有感(93):贪心算法——无重叠区间(区间重叠问题:求区间重叠次数)

题干: 代码&#xff1a; class Solution { public:static bool cmp(vector<int>& a, vector<int>& b){return a[0] < b[0];}int eraseOverlapIntervals(vector<vector<int>>& intervals) {sort(intervals.begin(), intervals.end(), c…

2024年湖北职称评审面试答辩技巧有哪些?看完你就懂了

2024年度湖北省部分工程专业水平能力测试面试答辩开始了&#xff0c;答辩时间是&#xff1a;2024年6月15、16日。 测试地点&#xff1a;武汉市武昌区洪山侧路63号茶港军转小区1号楼(武汉大学西门旁) 水平能力测试注意事项&#xff1a; &#xff08;一&#xff09;报名参加202…

企业级数据保护:华企盾DSC敏感内容识别与加密技术

在当今数字化时代&#xff0c;企业面临的数据安全挑战日益严峻。敏感数据的泄露不仅会导致经济损失&#xff0c;还可能损害企业的声誉和客户信任。因此&#xff0c;采用先进的敏感内容识别和加密技术&#xff0c;例如华企盾DSC敏感内容识别&#xff0c;对企业数据进行有效保护至…

Ubuntu server 24 (Linux) IPtables 双网卡 共享上网NAT 安装配置DHCP

一 开启路由转发功能 sudo vim /etc/sysctl.conf net.ipv4.ip_forward1 sudo sysctl -p 二 安装DHCP #更新软件包列表&#xff1a; sudo apt update #安装DHCP服务器 sudo apt install isc-dhcp-server #修改监听网卡,根据实际修改 sudo vi /etc/default/isc-dhcp-server …

【动手学深度学习】使用块的网络(VGG)的研究详情

目录 &#x1f30a;1. 研究目的 &#x1f30a;2. 研究准备 &#x1f30a;3. 研究内容 &#x1f30d;3.1 多层感知机模型选择、欠拟合和过拟合 &#x1f30d;3.2 练习 &#x1f30a;4. 研究体会 &#x1f30a;1. 研究目的 理解块的网络结构&#xff1b;比较块的网络与传统…

AI 入门指南二 :AI提示词(Prompt)

一&#xff0c;提示词的定义 提示词在中文中意为“触发”&#xff0c;在自然语言处理&#xff08;NLP&#xff09;的领域&#xff0c;它更接近于一个“心领神会”的概念&#xff0c;而非具有明确定义的术语。 简而言之&#xff0c;提示词是用户对大型语言模型的输入&#xff0…

Qt | Qt 资源简介(rcc、qmake)

1、资源系统是一种独立于平台的机制,用于在应用程序的可执行文件中存储二进制文件(前面所讨论的数据都存储在外部设备中)。若应用程序始终需要一组特定的文件(比如图标),则非常有用。 2、资源系统基于 qmake,rcc(Qt 的资源编译器,用于把资源转换为 C++代码)和 QFile …

EE trade:通货膨胀对老百姓意味着什么

通货膨胀&#xff0c;是经济领域中的一个常见现象&#xff0c;对社会各阶层尤其是普通老百姓的生活产生了深远影响。理解通货膨胀对老百姓的真实含义&#xff0c;可以帮助我们更好地应对日常生活的变化与挑战。 1. 生活成本的上升 最直接的影响体现在生活成本上。通货膨胀会导致…

音频pop音的数学与物理解释

音频数据跳变太大的时候通常会有pop音&#xff0c;此时频谱上看pop音位置能量较高 音频中的“pop”音通常是由于信号的不连续性或瞬态变化造成的。这种不连续性的数学和物理原因可以从以下几个方面解释&#xff1a; 数学解释 信号不连续性 当音频信号发生突变时&#xff0c;…

Android完整备份:备份Android手机数据的4种最佳方法

如今&#xff0c;人们每天都依赖手机&#xff0c;丢失数据对我们所有人来说都是一个大麻烦。由于生活是不可预测的&#xff0c;没有人知道什么时候他的数据可能会被意外删除或丢失。因此&#xff0c;仔细备份手机数据非常重要。大多数主要智能手机平台都具有将数据备份到计算机…

C/C++学习路线

学习分享 C语言学习路线 视频&#xff1a;浙大翁恺C语言程序设计&#xff0c;当时学习C语言的时候感觉老师讲的很有意思&#xff0c;现在依然很受学生欢迎&#xff0c;播放量也很高&#xff0c;C语言主要需要学习数组&#xff0c;指针&#xff0c;结构体和函数等&#xff0c;…

爆肝三天,制作属于自己的地图——DAY1(地图数据整理)

爆肝第一天&#xff0c;地图数据整理 作者&#xff1a;御剑飞行 引言 本系列我将用三篇文章详细的讲述开源地图数据集、Mapmost Studio介绍、如何通过Mapmost Studio转为生成地图数据。 以下是常用的地图数据集。 Esri 开放数据中心 Esri开放数据中心包含来自全球5,000 多…

【AI基础】第四步:保姆喂饭级-langchain+chatglm2-6b+m3e-base

在第三步手动安装chatglm2-6b时&#xff0c;已经可以通过web进行交互。langchain重新封装了一下AI框架&#xff0c;提供更加友好的开发功能&#xff0c;类似于AI届的spring框架。langchain的安装过程也类似于上一步说的&#xff1a;【AI基础】第三步&#xff1a;纯天然手动安装…

SwiftUI知识点(一)

前言&#xff1a; Swift知识点&#xff0c;大至看完了&#xff0c;公司项目是Swift语言写的&#xff0c;后续苹果新出的SwiftUI&#xff0c;也需要学习一下 不知觉间&#xff0c;SwiftUI是19年出的&#xff0c;现在24年&#xff0c;5年前的东西了 学习的几个原因&#xff1a; …