Java基础学习---3、堆、GC

news2025/2/23 1:09:53

1、堆

1.1 概述

1.1.1 堆空间结构

在这里插入图片描述

1.1.2 堆空间工作机制
  • 新创建的对象会放在Eden区
  • 当Eden区中已使用的空间达到一定比例,会触发Minor GC
  • 每一次在Minor GC中没有被清理掉的对象就成了幸存者。
  • 幸存者对象会被转移到幸存者区
  • 幸存者区分成from区和to区
  • from区快满的时候,会将仍然在使用的对象转移到to区
  • 然后from和to这两个指针彼此交换位置
    口诀:复制必交换,谁空谁为to
  • 如果一个对象,经历15次GC仍然幸存,那么它将会被转移到老年代
  • 如果幸存者区已经满了,即使某个对象尚不到15次,仍然会被移动到老年代
  • 最终效果:
    • Eden区主要是生命周期很短的对象来来往往
    • 老年代主要是生命周期很长的对象。例如:IOC容器对象、线程池对象、数据库连接池对象等等。
    • 幸存者区作为两者之间的过度地带
  • 关于永久代
    • 从理论上来说属于堆
    • 从具体实现上来说不属于堆
1.1.3堆、栈、方法区之间关系

在这里插入图片描述

1.1.4 常驻Web对象存活时间

生产环境下:
ServletContext存活时间:
时间单位:月、年
HttpSession存活时间:
时间单位:分钟、小时
HttpServletRequest存活时间:服务器端接收到请求~服务器提交响应
时间单位:秒或毫秒
HttpServletResponse存活时间:服务器端接收到请求~服务器给客户端返回了响应数据
时间单位:秒或毫秒

2.GC

为什么要有垃圾回收?

  • 线程私有空间:无需由系统来执行GC。因为线程结束,释放自己刚才使用的空间即可,不影响其它线程。

  • 线程共享空间:任何一个线程结束时,都无法确定刚才使用的空间是不是还有别的线程在使用。所以不能因为线程结束而释放空间,必须在系统层面统一垃圾回收。
    GC的基本原则:

    • 频繁收集新生代
    • 较少收集老年代
    • 基本不动元空间

2.1 标记垃圾对象

垃圾对象的标准:不再被引用的对象。下面这两种方法都是要把这样的对象找出来。

1、引用计数法(不采用)
(1)本意

  • 在对象内部记录被引用次数
  • 被引用一次,计数器+1
  • 引用解除一个,计数器-1
  • 计数器归零则表示该对象变成垃圾

(2)问题
循环引用问题,会导致计数器无法归零。

2、GC Roots可达性分析
核心原理:判断一个对象,是否存在从堆外到堆内的引用

因为我们写Java代码时,是不可能直接访问到堆内对象的,要么是通过方法里面局部变量,要么通过static修饰的常量、类变量。局部变量、类变量、常量这些都在堆外。

3、GC Root对象
GC Root对象:就是作为根节点出发,顺着引用路径一直查找到堆空间内,找到堆空间中的对象。

  • 虚拟机栈(Java Stack栈帧中的局部变量区,也叫局部变量表)中引用的对象
  • 本地方法栈(Native Method Stack)中的局部变量
  • 方法区中的类变量、常量引用的对象(说白了就是用static修饰的成员变量指向的对象)

2.2 垃圾回收算法

1、回收范围
在这里插入图片描述
JVM在进行GC时,并非每次都对上面三个内存区域一起回收的,大部分时候回收的都是指新生代。

  • minor GC:只针对新生代区域的GC,指发生在新生代的垃圾收集动作。
    因为大多数Java对象存活率都不高,所以Minor GC非常频繁,一般回收速度也比较快。

  • major

    • 对老年代的垃圾回收
    • Major GC的速度一般会比Minor GC慢10倍以上,STW的时间更长
    • 如果Major GC后,内存还不足,就报OOM了。
  • full GC:清理范围包括新生代、老年代和方法区,非常慢。

2、GC年龄
新生代的对象每经历一次GC,只要它还活着,GC年龄就会+1.当GC年龄达到15的时候,该对象就会转移到老年代。
对象在新生代的最大GC年龄可以设置:

-XX:MaxTenuringThreshold

从JDK8开始,64位虚拟机的最大GC年龄不能超过15。

2.2.1 基本算法

1、引用计数法(不采用)
优点:

  • 实时性较高,不需要等到内存不够时才回收
  • 垃圾回收时不用挂起整个程序,不影响程序正常运行

缺点:

  • 回收时不移动对象,所以会造成内存碎片问题
  • 不能解决对象间的循环引用问题(致命问题,一票否决)

小结:
正是由于引用计数法不能解决对象间的循环引用问题,所以事实上并没有哪一款JVM产品采用这个机制。

2、标记清除法
它的做法是当堆中的有效内存空间被耗尽时,就会暂停、挂起整个程序(也被称为stop the world),然后进行两项工作,第一项则是标记,第二项则是清除。

  • 标记:标记的过程其实就是从根对象开始变量所以得对象,然后将所有存活的对象标记为可达对象。
  • 清除:清除的过程中将遍历堆中的所有对象,将没有标记的对象全部清除掉。
    小结:
  • 优点:实现简单
  • 缺点:
    • 效率低,因为标记和清除两个动作都有遍历所有的对象
    • 垃圾收集后可能会造成大量·的内存碎片
    • 垃圾回收时会造成应用程序暂停

在这里插入图片描述
3、标记压缩法
既然教标记压缩算法,那么它也分为两个阶段,一个时标记(mark),一个时压缩(compact)。所谓压缩就是把存在碎片的空间连起来。
标记压缩算法是在标记清除算法的基础之上,做了优化改进的算法。和标记清除算法一样,也是从根节点开始,对对象的引用进行标记,在清理阶段,并不是简单的清理未标记的对象,而是将存活的对象移动到内存的一端,然后清理边界以外的垃圾,从而解决了碎片化的问题。

  • 标记:标记的过程其实就是从根对象开始遍历所以对象,然后将所有存活的对象标记为可达的对象。
  • 压缩:移动所以的可达对象到堆内存的同一个区域中,使它们紧凑的排列在一起,从而将所有非可达对象释放出来的空闲内存都集中在一起,通过这样的方式来达到减少内存碎片的目的。

小结

  • 优点:标记压缩算法是对标记清除算法的优化,解决了碎片化的问题
  • 缺点:还是效率问题,在标记清除算法上又多加了一步,效率就更低了

在这里插入图片描述

4、复制算法
复制算法的核心就是将原有的内存空间一分为二,每次只用其中的一块,在进行垃圾回收时,将正在使用的对象复制到另一个内存空间中,并依次排列,然后将该内存空间清空,交换两个内存的角色,完成垃圾的回收。

小结:

  • 优点:
    • 在垃圾多的情况下(新生代),效率比较高
    • 清理后,内存无碎片
  • 缺点:
    • 浪费了一般的内存空间,在存活对象比较多的情况下(老年代),效率较差。极端情况下,如果假设所有对象存活,那么需要复制全部对象且重置全部引用地址。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2.2 综合算法

1、分代算法
前面介绍了多种回收算法,每一种算法都有自己的优点也有缺点,谁都不能替代谁,所以根据垃圾回收对象的特点进行选择,才是明智的。

分代算法其实就是这样的,根据回收对象的特点进行选择。

新生代适合使用复制算法
老年代适合使用标记清除或标记压缩算法

2、分区算法
上面介绍的分代收集算法是将对象的生命周期按长短划分为两个部分,而分区算法则将整个堆空间划分为连续的不同小区间,每个小区间独立使用,独立回收。这样做的好处是可以控制一次回收多少个小区间。在相同条件下,堆空间越大。一次GC耗时就越长,从而产生的停顿也越长。为了更好地控制GC产生的停顿时间,将一块大的内存区域分割为多个小块,根据目标停顿时间每次合理地回收若干个小区间(而不是整个堆),从而减少一次GC所产生的停顿。

2.3 垃圾回收器

垃圾回收器没有在规范中进行过多的规定,可以由不同厂商、不同版本的JVM来各自实现。由于JDK的版本处于高速迭代过程中,因此Java发展至今已经衍生了众多的垃圾回收器产品。从不同角度分析垃圾回收器,可以将GC分为不同的类型。

在JVM中,垃圾回收器可以按照并行和串行两种方式工作。

串行垃圾回收器一次只能使用一个线程进行垃圾回收,也就是在垃圾回收期间,JVM将停止应用程序的执行,直到垃圾回收完成为止。这种回收器适用于单处理器环境下或者是在较小的堆内存中使用。

并行垃圾回收器会使用多个线程来加快垃圾回收的速度。这种回收器通常比串行垃圾回收器速度更快,但需要更多的CPU和内存资源。在垃圾回收期间,应用程序可能需要被暂停,但停顿时间比串行垃圾回收器要短。

总的来说,串行垃圾回收器适用于小型应用并且操作系统资源有限的情况下,而并行垃圾回收器适用于大型应用和高性能服务器,当然这也要看具体应用场景的需求。

2.3.1串行垃圾回收器

串行:在一个线程内执行垃圾回收操作

新生代串行回收器 SerialGC:采用复制算法实现,单线程垃圾回收,独占式垃圾回收器。

新生代串行回收器 SerialGC:采用复制算法实现,单线程垃圾回收,独占式垃圾回。

2.3.2并行垃圾回收器

并行:在多个线程中执行垃圾回收操作。
新生代 ParNew 回收器:采用复制算法实现,多线程回收器,独占式垃圾回收器。
新生代 ParallelScavengeGC 回收器:采用复制算法多线程独占式回收器。
新生代 ParNew 回收器:采用复制算法实现,多线程回收器,独占式垃圾回收器。

  • CMS回收器
    CMS全称 (Concurrent Mark Sweep),是一款并发的、使用标记-清除算法的垃圾回收器。对CPU资源非常敏感。
    启用CMS回收器参数 :-XX:+UseConcMarkSweepGC。
    使用场景:GC过程短暂停顿,适合对时延要求较高的服务,用户线程不允许长时间的停顿。
    优点:最短回收停顿时间为目标的收集器。并发收集,低停顿。
    缺点:服务长时间运行,造成严重的内存碎片化。算法实现比较复杂。
  • G1回收器
    G1(Garbage-First)是一款面向服务端应用的并发垃圾回收器, 主要目标用于配备多颗CPU的服务器,治理大内存。是JDK1.7提供的一个新收集器,是当今收集器技术发展的最前沿成果之一。
    G1计划是并发标记-清除收集器的长期替代品。
    启用G1收集器参数:-XX:+UseG1GC启用G1收集器。
    G1将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了, 它们都是一部分Region(不需要连续)的集合。
2.3.3垃圾回收器对比

1、新生代回收器

名称串行/并行/并发回收算法
SerialGC串行复制
ParNew并行复制
ParallelScavengeGC并行复制
(1)SerialGC
SerialGC是JVM中最基本的垃圾回收器,也是串行垃圾回收器的一种实现。SerialGC在进行垃圾回收时只会使用一个线程,因此它的回收效率不高,但可以保证垃圾回收过程不会影响应用程序的并发执行。

SerialGC主要用于小型应用程序或者只使用单核CPU的环境下,它的优点是实现简单、消耗内存较少,缺点是效率较低,在大型应用程序或需要高性能的环境中表现不佳。在JDK9之前,它是默认的垃圾回收器。但在JDK9以后,G1成为了默认垃圾回收器。

由于SerialGC无法满足大型应用程序的需求,因此在多核CPU环境下,通常会采用并发垃圾回收器或者并行垃圾回收器来提高垃圾回收效率。

(2)ParNewGC
ParNewGC是JVM中支持多线程并行垃圾回收的垃圾回收器之一,它可以与CMS(Concurrent Mark Sweep)垃圾回收器配合使用,提高垃圾回收效率。

与SerialGC不同,ParNewGC可以使用多个线程来并发执行垃圾回收,从而充分利用多核CPU的优势。同时,ParNewGC还具有一定的并发能力,可以允许应用程序在垃圾回收过程中继续执行。

ParNewGC主要用于需要高性能的大型Java应用程序中,它的优点是能够充分利用CPU资源,加速垃圾回收过程,缺点是可能会增加一定的内存消耗,因为需要使用多个线程来执行垃圾回收。

需要注意的是,ParNewGC只能与CMS垃圾回收器结合使用,由于CMS垃圾回收器会解决的问题,ParNewGC并不能完全解决,因此在使用时需要进行适当的配置和调优。

(3)ParallelScavengeGC
ParallelScavengeGC是Java Virtual Machine (JVM) 默认的垃圾回收器之一,它属于并行垃圾回收器的一种。它的主要特点是在垃圾回收处理期间,会同时通过多个线程来处理垃圾回收,从而提高回收效率。

ParallelScavengeGC是一个适用于多核处理器的垃圾回收器,在大量并发系统中得到了广泛的应用。ParallelScavengeGC的主要任务是尽可能地减少应用程序的停顿时间,并且尽可能地提高垃圾回收的效率,对于需要高吞吐量的应用程序而言是一个非常好的选择。

ParallelScavengeGC将整个堆内存分成多个大小相等的区域(即各个Eden区和Survivor区),各个区域之间是等大小的,它通过多个线程同时回收各个区域中的垃圾,从而保证了垃圾回收的高速执行。同时,它还使用了一种“分代”概念,将堆内存划分为年轻代和老年代,以便更好地处理这些区域内不同生命周期的对象。

总之,ParallelScavengeGC是一种高吞吐量、低延迟的垃圾回收器,它适用于需要快速处理大量垃圾的并发应用程序,同时还能够提高Java程序的性能和可扩展性。

2、老年代回收期

名称串行/并行/并发回收算法
SerialOldGC串行标记压缩算法
ParNewOld并行标记压缩算法
CMS并行,几乎不会暂停用户线程标记压缩算法
(1)SerialOldGC
Serial Old GC是Java虚拟机中的一个垃圾回收器,主要用于回收Java堆中的老年代空间。与其配对使用的新生代垃圾回收器是Serial GC,两者共同组成了Java虚拟机中的默认垃圾回收器组合。

Serial Old GC采用的是“标记-整理”(Mark-Compact)的算法,它首先标记需要回收的内存块,然后将所有存活的对象向一端移动,最终在堆的另一端清理出空闲空间。由于Serial Old GC是串行回收器,因此它只能使用单个线程进行垃圾回收操作。

Serial Old GC的优点是简单可靠,由于采用串行回收的方式,可以消除线程同步的开销和复杂度,因此在小型应用程序和较老的硬件上性能表现较好。然而,由于其无法并发执行,因此在大型应用程序和现代硬件上的性能表现较为糟糕,会导致较长的应用程序暂停时间。

总的来说,Serial Old GC是一种适用于小型Java应用程序和较老硬件的垃圾回收器,在性能表现方面有一定局限性。
(2)ParNewOldGC
ParNewOldGC是Java虚拟机中的一种垃圾回收器组合,由ParNew GC和CMS GC两部分组成。

ParNew GC是一个多线程的垃圾回收器,主要用于回收Java堆中的新生代空间。它采用的是“标记-复制”(Mark-Copy)算法,首先标记需要回收的内存块,然后将存活的对象复制到另外一个空间中,并清理原有内存空间。由于ParNew GC是多线程回收器,可以并行执行垃圾回收操作,因此它能够充分利用多处理器系统和多核心CPU的优势,提高垃圾回收的效率。

CMS GC(Concurrent Mark Sweep GC)是一种并发的垃圾回收器,主要用于回收Java堆中的老年代空间。它采用“标记-清除”(Mark-Sweep)的算法,因此它能够在应用程序运行的同时执行垃圾回收操作,减少应用程序暂停的时间。不过,CMS GC回收老年代内存需要牺牲部分应用程序运行时间,因为它需要暂停应用程序执行一段时间来完成标记和清理操作。

ParNewOldGC将ParNew GC和CMS GC组合起来,可以充分利用多线程和并发执行的优势,减少Java堆内存回收过程中的延迟时间和应用程序暂停时间,同时保证系统吞吐量和性能。它适用于多核心CPU和高并发场景下的Java应用程序。
(3)Concurrent Mark Sweep(CMS)

Concurrent Mark Sweep(CMS)是一种针对大型Java应用程序的垃圾回收器。它使用多个线程来在垃圾回收过程中并发执行标记和清除操作,从而最大程度地减少应用程序的停顿时间。

CMS垃圾回收器采用了一种“标记-清除”(Mark-Sweep)的算法,它通过标记需要回收的内存块,并在回收时进行清除操作。CMS垃圾回收器在标记和清除操作中采用了一些优化措施,例如:使用“写屏障”和“增量标记”等技术来避免在标记和清除过程中出现大量的停顿时间。

由于CMS垃圾回收器是一种并发垃圾回收器,因此它可以在应用程序运行过程中进行垃圾回收操作,大大减少了应用程序的停顿时间。但是,CMS垃圾回收器也存在一些缺点,例如:由于在并发垃圾回收过程中需要保证内存一致性,它可能会导致一些内存资源的浪费和系统的性能下降。

总的来说,CMS垃圾回收器主要适用于大型Java应用程序,它可以通过优化标记和清除过程、减少停顿时间等方式提高系统的性能和吞吐量。

2.3.4查看当前JVM的垃圾回收器

1、Java程序启动时添加以下JVM参数,可以在控制台输出JVM的GC信息:

-XX:+PrintGC

2、该参数只会输出简单的GC日志信息,如果需要输出详细的日志信息,可以使用以下JVM参数:

-XX:+PrintGCDetails

3、在输出的日志信息中查找以下关键字,即可确定当前JVM使用的具体垃圾回收器:

  • PSYoungGen 和 ParNew 表示使用的是Parallel Scavenge收集器
  • PSOldGen 和 ConcurrentMarkSweep 表示使用的是Parallel Old收集器
  • G1 Young Generation 和 G1 Old Generation 表示使用的是Garbage-First收集器
[Full GC (Ergonomics) [PSYoungGen: 128K->0K(8192K)] [ParOldGen: 0K->14041K(17408K)] 128K->14041K(25600K), [Metaspace: 2577K->2577K(1056768K)], 0.0129332 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]

2.4 finalize机制

1、总体介绍
java.lang.Object 类中有一个方法:

protected void finalize() throws Throwable { }

方法体是空的,说明如果子类不重写这个方法,那么不执行任何逻辑。
在这里插入图片描述

  • 在执行GC操作之前,调用finalize()方法的是Finalizer线程,这个线程的优先级很低。
  • 在对象的整个生命周期过程中,finalize()方法只会被调用一次。
    2、代码验证
public class FinalizeTest {

    // 静态变量
    public static FinalizeTest testObj;

    @Override
    protected void finalize() throws Throwable {
        // 重写 finalize() 方法
        System.out.println(Thread.currentThread().getName() + " is working");

        // 给待回收的对象(this)重新建立引用
        testObj = this;
    }

    public static void main(String[] args) {

        // 1、创建 FinalizeTest 对象
        FinalizeTest testObj = new FinalizeTest();

        // 2、取消引用
        testObj = null;

        // 3、执行 GC 操作
        System.gc();

        // ※ 让主线程等待一会儿,以便调用 finalize() 的线程能够执行
        try { TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {}

        // 4、判断待回收的对象是否存在
        if (FinalizeTest.testObj == null) {
            System.out.println("待回收的对象没有获救,还是要被 GC 清理");
        } else {
            System.out.println("待回收的对象被成功解救");
        }

        // 5、再次取消引用
        FinalizeTest.testObj = null;

        // 6、再次执行 GC 操作
        System.gc();

        // 7、判断待回收的对象是否存在
        if (FinalizeTest.testObj == null) {
            System.out.println("待回收的对象没有获救,还是要被 GC 清理");
        } else {
            System.out.println("待回收的对象被成功解救");
        }
    }

}

执行效果:
在这里插入图片描述

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

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

相关文章

如何提高软件复用度,降低项目开发成本?

1、代码基线管控策略 理想的代码复用是我们建立一条主干代码,持续维护下去。面对客户的新需求,需要我们拉一条临时分支来满足客户需求,然后将稳定后的临时分支代码成果回归到主干。这样我们所有的研发成果都可以在一个代码分支上进行追溯&…

FreeRTOS学习之路,以STM32F103C8T6为实验MCU(序章——浅谈单片机以及FreeRTOS)

学习之路主要为FreeRTOS操作系统在STM32F103(STM32F103C8T6)上的运用,采用的是标准库编程的方式,使用的IDE为KEIL5。 注意!!!本学习之路可以通过购买STM32最小系统板以及部分配件的方式进行学习…

论文解读 | 透过窥镜: 透明容器内物体的神经三维重建

原创 | 文 BFT机器人 随着虚拟现实和虚拟世界技术的发展,博物馆藏品的数字化是一个越来越受关注的新兴话题。世界上许多著名的博物馆都在为网上展览建立自己的数字馆藏。 在这些藏品中,有一种特殊而重要的藏品昆虫、人体组织、水生生物和其他易碎的标本需…

ZooKeeper(一):基础介绍

文章目录 什么是 ZooKeeper?ZooKeeper 发展历史ZooKeeper 应用场景ZooKeeper 服务的使用ZooKeeper 数据模型data tree 接口znode 分类 总结 什么是 ZooKeeper? ZooKeeper 是一个分布式的,开放源码的分布式应用程序协同服务。ZooKeeper 的设计…

docker-compose安装nacos 2.2.1及配置

目录 官网 创建存储目录 创建数据库 application.properties配置(重要) docker-compose.yml 启动 登录 下面是安装nacos 2.2.1版本的方法,有一些变化 官网 GitHub - alibaba/nacos: an easy-to-use dynamic service discovery, configu…

SCTracker 跟踪论文阅读笔记

SCTracker 跟踪论文阅读笔记 SCTracker: Multi-object tracking with shape and confidence constraints 论文链接 (未开源状态) 论文主要更新点围绕shape constraint and confidence两点来展开: 首先论证在跟踪匹配的过程中D-box(检测框)与T-box(预测框)需要有一定…

今日的CSS小案例

个人名片: 😊作者简介:一名大一在校生,web前端开发专业 🤡 个人主页:几何小超 🐼座右铭:懒惰受到的惩罚不仅仅是自己的失败,还有别人的成功。 🎅**学习目…

第一篇、基于Arduino uno,获取dht11温湿度传感器的温度信息和湿度信息——结果导向

0、结果 说明:先来看看串口调试助手显示的结果,如果是你想要的,可以接着往下看。 1、外观 说明:虽然dht11温湿度模块形态各异,但是代码都是适用的,因为它们的模块都是一样的。 2、连线 说明:…

微博开发--微博官方API使用方法【从注册到实战】

第一步:微博开发者身份认证 访问微博开放平台,登录自己微博账号,登录之后首先需要完善开发者的基本信息。【使用个人】 填写完成之后【审核通过】如下: 第二步:创建自己的应用 【备注:如果只是为了测试…

逻辑回归及逻辑回归的评估指标

一、逻辑回归介绍 逻辑回归(Logistic Regression)是机器学习中的一种分类模型,逻辑回归是一种分类算法,虽然名字中带有回归,但是它与回归之间有一定的联系。由于算法的简单和高效,在实际中应用非常广泛。 1.逻辑回归的应用场景 …

【腾讯云FinOps Crane 集训营】快速搭建一个 Kubernetes+Crane 环境,以及如何基于 Crane 优化你的集群和应用初体验

文章目录 一、活动介绍二、环境搭建三、安装本地的 Kind 集群和 Crane 组件四、界面截图五、主要功能六、整体架构七、Crane的优势八、总结参考文献 一、活动介绍 Crane 是由腾讯云主导开源的国内第一个基于云原生技术的成本优化项目,遵循 FinOps 标准,…

用java带你了解网络IO模型

目录 1.BIO1.1 简述1.2 代码示例1.3优点和缺点1.4 思考 2. NoBlockingIO2.1 简述2.2 代码示例2.3 优点和缺点2.4 思考 3. NIO(NewIO)3.1 简述3.2 代码示例3.3 优点和缺点3.3 思考 4. 扩展select/poll、epoll4.1 简述4.2 select/poll4.3 epoll4.4 扩展话题…

Linux之vim编辑器的使用

目录 一、vim是什么? 试验1: 二.命令模式继承用法: vim命令模式的快捷键: 光标移动: vim文本复制相关操作: vim文本编辑操作: 三.末行模式命令用法 部分快捷键: 四.vim编辑器的配置原理 一、vim是什么? vi…

Hive SQL语句的正确执行顺序

关于 sql 语句的执行顺序网上有很多资料,但是大多都没进行验证,并且很多都有点小错误,尤其是对于 select 和 group by 执行的先后顺序,有说 select 先执行,有说 group by 先执行,到底它俩谁先执行呢&#x…

智能结构诊断器:建筑结构健康的守护者

近年来,接二连三的自建房坍塌,超高层建筑震动,让建筑的健康和安全性成为了人们关注的焦点。为了确保建筑物的长期稳定性和安全性,迫切需要高效且准确的方法来监测结构的健康状况。智能结构诊断器的出现,让建筑结构监测…

大数据如何助力营销(5)活动复盘

在市场竞争日益激烈的今天,营销活动已经成为吸引用户、提升品牌影响力、增加销售转化的重要手段。然而,一场营销活动在举办后,往往难以评估活动的效果,而大数据技术将从方方面面、科学有效地复盘活动,并为下一次举办活…

chatgpt赋能Python-python_kbhit

Python kbhit - 帮助您掌握实时按键输入 如果您需要使用实时按键输入来控制您的Python程序,那么你需要知道的是Python kbhit。kbhit是一种允许用户实时按键输入并立即响应的技术。本文将介绍Python kbhit的用途和用法,并探讨实时输入如何帮助您掌控程序…

AI绘图学习心得分享-Midjourney绘画AI,让你少走一些弯路

本教程收集于:AIGC从入门到精通教程 AI绘图学习心得分享-Midjourney绘画AI,让你少走一些弯路 本篇没有什么长篇大论,全部都是实用心得总结。接下来,我们将分享关于Midjourney绘画AI的实用心得总结,包括构图指令结构、常用指令、操作技巧、常用风格词汇和构图词汇。 如果…

手机号码在网时长 API 实现广告投放和精准营销案例分析

引言 手机在网时长是指用户在移动网络上的在线时间,包括用户接入网络的时间和断开网络的时间。手机在网时长 API 是一种提供手机在网时长数据的编程接口,为开发者和服务提供商提供了获取和利用这些数据的能力。 本文旨在深入探讨手机在网时长 API 的技…

计算机视觉——day95 PANet:基于样本原型对齐的Few-Shot图像语义分割

PANet:基于样本原型对齐的Few-Shot图像语义分割 1. Introduction2. Related workFew-shot segmentation 3. Method3.1. Problem setting3.2. Method overview3.3. Prototype learning(原型学习)3.4. 非参数度量学习3.5. 原型对准正则化(PAR) 4. Experime…