JVM基础

初识JAM

JVM就是JAVA虚拟机,本质上是一个运行在计算机上的程序,他的职责是运行JAVA字节码文件.

下面是java代码执行过程

JVM的功能

1.解释和运行

  • 对字节码文件中的指令实时的解释成机器码

2.内存管理

  • 自动为对象,方法等分配内存
  • 自动的垃圾回收机制,回收不再使用的对象

3.即时编译

  • 对热点代码进行优化,提升执行效率

即时编译解释:

Java需要将字节码文件的字节码指令用JVM实时编译成机器码交给计算机运行,实现了跨平台特性,在不做优化性能不如c语言

虚拟机如果发现字节码文件中有多次调用的热点代码,会主动将其优化成机器码,并保存在内存中,当下次执行可以直接调用。

常见的JVM选择:

JVM的组成

1.类加载器

首先要把字节码文件加载到内存中

2.运行时数据区域(JAM管理的内存)

虚拟机要准备一块内存空间去管理字节码文件中的类,对象,接口

3.执行引擎(即时编译器,解释器,垃圾回收器等)

将字节码文件的指令解释成机器码,同时使用编译器优化性能

4.本地接口

虚拟机使用的是c/c++来编写,虚拟机在运行是要调用底层虚拟机实现的c编写的不存在于字节码文件中的方法

字节码文件

字节码文件的组成

1.基础信息

魔数,字节码文件对应的java版本号,访问标识(public,final等等),父类和接口

魔数:

文件是通过文件头校验文件类型,魔数是class字节码文件的校验类型文件头

版本号:

2.常量池

保存了字符串常量,类或接口名,字段名 等,主要在字节码指令中使用

作用:避免重复定义内容,节省空间。

  • 常量池的数据有一个编号,编号从1开始。在字段或者字节码指令中通过编号可以快速的找到对应的数据。
  • 字节码指令中通过编号引用到常量池的过程称为符号引用

举个例子:先定义三个字符串

我们来查看以下字节码文件:

我们可以看到内容是一个索引跟进后发现还是一个索引

再次跟进找到了常量abc的值

这是将字符串常量先进行了一个分类。能够将其他常量进行区分,例如下面变量名也是abc的情况

3.字段

类和接口声明的字段信息

4.方法

当前类或接口声明的方法信息,字节码指令

5.其他

类的属性,比如源码的文件名,内部类的列表等

类的生命周期

1.加载阶段

  • 1.加载阶段第一步是类加载器通过全限定名通过不同的渠道以二进制流的方式获取字节码信息。
  • 2.类加载器加载完类之后,java虚拟机会将字节码中的信息保存到方法区中,生成一个InstanceKlass对象,保存类的所有信息,里面还包含特定功能比如多态的信息
  • 3.java虚拟机还会在堆中生成一份与方法区中类似的java.lang.class对象,作用是反射时候获取信息和存储静态字段的数据。

 对于开发者来说,只需要访问堆中的Class对象而不需要访问方法区中所有信息。
这样Java虚拟机就能很好地控制开发者访问数据的范围。例如堆区中的对象不包含虚方法表

2.连接阶段

  • 连接的第一个环节是验证,验证的主要目的是检测java字节码文件是否遵守了《java虚拟机规范》中的约束。这如果不规范就会类加载失败,并且抛出异常。验证选项有:文件格式验证,字节码验证,符号引用验证。
  • 给静态变量分配内存,并且设置类变量的初始值。
  • 解析阶段主要是将常量池中的符号引用替换为直接引用。符号引用就是在字节码文件中使用编号来访问常量池中的内容。直接引用是使用内存中的地址进行访问具体的数据

3.初始化

  • 初始化阶段会执行静态代码块中的代码,并为静态变量赋值。
  • 初始化阶段会执行字节码文件中clinit部分的字节码指令。

以下几种方式会导致类的初始化:
1.访问一个类的静态变量或者静态方法,注意变量是final修饰的并且等号右边是常量不会触发初始化。
2.调用Class.forName(String className)。
3.new一个该类的对象时。
4.执行Main方法的当前类。

clinit指令在特定情况下不会出现,比如:如下几种情况是不会进行初始化指令执行的。

1.无静态代码块且无静态变量赋值语边句。
2.有静态变量的声明,但是没有赋值语句。
3.静态变量的定义使用final关键字,这类变量会在准备阶段直接进行初始化。

  1. 类加载阶段会进行 静态代码块 的执行,想要创建实例,势必要先进行类加载。
  2. 静态代码块只是在类加载阶段执行一次。
  3. 构造方法和构造代码块,每次实例化都会执行,构造代码块在构造方法前面。

类加载器

类加载器(ClassLoader)是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术。

类加载器的分类:

类加载器分为两类,一类是在java代码中实现的,一类是java虚拟机底层源码实现的

虚拟机底层源码实现的有一个类加载器叫启动类加载器(用来加载java中最核心的类)

java代码中实现的有扩展类加载器应用类加载器,它们的源码都位于sun.misc.Launcher中,是一个静态内部类。继承自URLClassLoader。具备通过目录或者指定jar包将字节码文件加载到内存中。

启动类加载器

  • 启动类加载器(Bootstrap ClassLoader)是由Hotspot虚拟机提供的、使用C++编写的类加载器。
  • 默认加载Java安装目录/jre/lib下的类文件,比如rt.jar,tools.jar, resources.jar#.

如图我们使用getClassLoader方法获取类加载器,可以看到输出结果为null,因为启动类加载器由虚拟机底层原理实现,出于安全考虑不能获取到。

让启动类加载器去加载用户jar包:

1.放入jre/lib下进行扩展

不推荐,尽可能要不去更收JDK安装目录中的内容,会出现即时放进去由于文件名不匹配的问题也不会正常地被加载

2.使用参数扩展

推荐,使用-Xbootclasspath/a:jar包目录/jar包名 进行扩展

扩展类加载器

扩展类加载器和应用程序类加载器都是JDK中提供的、使用Java编写的类加载器。
默认加载Java安装目录下/jre/lib/ext下的类文件

通过扩展类加载器去加载用户jar包:

1.放入/jre/lib/ext下进行扩展不推荐,尽可能不要去更改JDK安装目录中的内容

2.使用参数进行扩展推荐,使用-D java.ext.dirs=jar包目录 进行扩展,这种方式会覆盖掉原始目录,可以用;(windows):(macos/linux)追加上原始目录

加载时地址最好用双引号引起来防止当成特殊字符干扰

应用程序加载器

加载classpath下的类文件,包括了用户自己编写和导入jar包的类和文件。

JDK8之后的类加载器

由于JDK9引入了module的概念,类加载器在设计上发生了很多变化。
1.启动类加载器使用Java编写,位于jdk.internal.loader.ClassLoaders类中。Java中的BootClassLoader继承自BuiltinClassLoader实现从模块中找到要加载的字节码资源文件。
启动类加载器依然无法通过java代码获取到,返回的仍然是null,保持了统一。

2、扩展类加载器被替换成了平台类加载器(Platform Class Loader)。平台类加载器遵循模块化方式加载字节码文件,所以继承关系从URLClassLoader变成了BuiltinClassLoader, BuiltinClassLoader实现了从模块中加载字节码文件。平台类加载器的存在更多的是为了与老版本的设计方案兼容,自身没有特殊的逻辑。

双亲委派机制 

双亲委派机制概念

1、当一个类加载器去加载某个类的时候,会自底向上查找是否加载过,如果加载过就直接返
回,如果一直到最顶层的类加载器都没有加载,再由顶向下进行加载。
2、应用程序类加载器的父类加载器是扩展类加载器,扩展类加载器的父类加载器是启动类加
载器。
3、双亲委派机制的好处有两点:第一是避免恶意代码替换JDK中的核心类库,比如
java.lang.String,确保核心类库的完整性和安全性。第二是避免一个类重复地被加载。

运行时数据区

程序计数器

  • 程序计数器是线程不共享的 ,每个线程都有单独的一个程序计数器
  • 作用是保存下一条指令的地址在哪 里。
  • 在多线程执行情况下,java虚拟机需要通过程序计数器记录cpu切换前解释执行到的那一条指令并继续解释运行

栈 

Java虚拟机栈(Java Virtual Machine Stack)采用栈的数据结构来管理方法调用中的基本数据,先
进后出(First In Last Out),每一个方法的调用使用一个栈帧(Stack Frame)来保存。

Java虚拟机栈随着线程的创建而创建,而回收则会在线程的销毁时进行。由于方法可能会在不同线
程中执行,每个线程都会包含一个自己的虚拟机栈。

java 遇到异常时候就是将栈帧从栈中弹出,打印栈帧的信息,所以打印出的方法顺序是跟执行使劲啊相反

栈帧组成:

1.局部变量表

  • 作用是保存在运行过程中存放的局部变量.编译成字节码文件时就可以确定局部变量表的内容
  • 栈帧中的局部变量表是一个数组,数组中每一个位置称之为槽(slot),long和double类型占用两个槽,其他类型占用一个槽。
  • 方法参数也会保存在局部变量表中,其顺序与方法中参数定义的顺序一致。
  • 局部变量表保存的内容有:实例方法的this对象,方法的参数,方法体中声明的局部变量。
  • 为了节省空间,局部变量表中的槽是可以复用的,一旦某个局部变量不再生效,当前槽就可以再次被使用。

public void test4(int k, int m){
{
int a = 1;
int b = 2;
}
{
int c = 1;
}
int i = 0;
long j = 1;
}

上述代码占用了5个槽。

2.操作数栈

  • 操作数栈是栈帧中虚拟机在执行指令过程中用来存放中间数据的一块区域。他是一种栈式的数据结构,如果一条指令将一个值压入操作数栈,则后面的指令可以弹出并使用该值。
  • 在编译期就可以确定操作数栈的最大深度,从而在执行时正确的分配内存大小。

3.帧数据

  • 当前类的字节码指令引用了其他类的属性或者方法时,需要将符号引用(编号)转换成对应的运行时常量池中的内存地址。动态链接就保存了编号到运行时常量池的内存地址的映射关系。
  • 方法出口指的是方法在正确或者异常结束时,当前栈帧会被弹出,同时程序计数器应该指向上一个栈帧中的下一条指令的地址。所以在当前栈帧中,需要存储此方法出口的地址。
  • 异常表存放的是代码中异常的处理信息,包含了异常捕获的生效范围以及异常发生后跳转到的字节码指令位置。

栈内存溢出

  • Java虚拟机栈如果栈帧过多,占用内存超过栈内存可以分配的最大大小就会出现内存溢出。
  • Java虚拟机栈内存溢出时会出现StackOverflowError的错误

java虚拟机栈设置大小

  • 要修改Java虚拟机栈的大小,可以使用虚拟机参数-Xss。
  • 语法 :- Xss栈大小
  • 单位:字节(默认,必须是1024的倍数)、k或者K(KB)、m或者M(MB)、g或者G(GB)

  • 每个线程只有一份堆,多个进程公用一个堆,创建出来的对象都在堆上。
  • 栈上的局部变量表中可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通过静态变量就可以实现对象在线程之间共享
  • 堆空间有三个需要关注的值,used total max。used指的是当前已使用的堆内存,total是java虚拟机已经分配的可用堆内存,max是java虚拟机可以分配的最大堆内存。
  • 随着堆中对象的增多当total可以使用的内存即将不足时,java虚拟机会继续分配内存给堆
  • 不是used=max=total的时候堆内存溢出,将在后面的垃圾回收机制进行讲解
  • 如果不设置任何的虚拟机参数,max默认是系统内存的1/4,total默认是系统内存的1/64。在实际应用中一般都需要设置total和max的值。

堆设置大小

  • 要修改堆的大小,可以使用虚拟机参数-Xmx(max最大值)和-Xms(初始的total)。
  • 语法 :- Xmx值 -Xms值
  • 单位:字节(默认,必须是1024的倍数)、k或者K(KB)、m或者M(MB)、g或者G(GB)
  • 限制:Xmx必须大于 2 MB,Xms必须大于1MB

方法区

类的元信息

方法区是用来存储每个类的基本信息(元信息),一般称之为InstanceKlass对象。在类的加载阶段完成。

运行时常量池

  • 存放的是字节码中的常量池内容
  • 字节码文件中通过编号查表的方式找到常量,这种常量池称为静态常量池。当常量池加载到内存中之后,可以通过内存地址快速的定位到常量池中的内容,这种常量池称为运行时常量池。

字符串常量池

字符串常量池存储在代码中定义的常量字符串内容。比如“123”这个123就会被放入字符串常量池。

JDK6之前的版本中,静态变量是存放在方法区中的,JDK7之后,静态变量存放在堆中的Class对象中

直接内存

直接内存(Direct Memory)并不在《Java虚拟机规范》中存在,所以并不属于Java运行时的内存区域。
在JDK 1.4中引入了NIO机制,使用了直接内存,主要为了解决以下两个问题:
1、Java堆中的对象如果不再使用要回收,回收时会影响对象的创建和使用。
2、IO操作比如读文件,需要先把文件读入直接内存(缓冲区)再把数据复制到Java堆中。现在直接放入直接内存即可,同时Java堆上维护直接内存的引用,减少了数据复制的开销。写文件也是类似的思路。

  • 要创建直接内存上的数据,可以使用ByteBuffer。
  • 语法: ByteBuffer directBuffer = ByteBuffer.allocateDirect(size);如果需要手动调整直接内存的大小,可以使用-XX:MaxDirectMemorySize=大小
  • 单位k或K表示千字节,m或M表示兆字节,g或G表示千兆字节。默认不设置该参数情况下,JVM自动选择最大分配的大小。

 垃圾回收

算法评判标准

1.stw

Java垃圾回收过程会通过单独的GC线程来完成,但是不管使用哪一种GC算法,都会有部分阶段需要停止所有的用户线程。这个过程被称之为Stop The World简称STW,如果STW时间过长则会影响用户的使用。

2.吞吐量

吞吐量指的是CPU用于执行用户代码的时间与CPU总执行时间的比值,即吞吐量=执行用户代码时间/(执行用户代码时间+GC时间)。吞吐量数值越高,垃圾回收的效率就越高。

3.最大暂停时间

就是stw时间最大值

3.堆使用效率
不同垃圾回收算法,对堆内存的使用方式是不同的。比如标记清除算法,可以使用完整的堆内存。而复制算法会将堆内存一分为二,每次只能使用一半内存。从堆使用效率上来说,标记清除算法要优于复制算法。

方法区回收

方法区能回收的内容需要同时满足以下三个条件

  • 此类所有实例对象都已经被回收,在堆中不存在任何该类的实例对象以及子类对象。
  • 加载该类的类加载器已经被回收。
  • 该类对应的java.lang.Class对象没有在任何地方被引用。

手动触发垃圾回收

  • 如果需要手动触发垃圾回收,可以调用System.gc()方法。
  • 语法:System.gc()
  • 注意事项:调用System.gc()方法并不一定会立即回收垃圾,仅仅是向Java虚拟机发送一个垃圾回收的请求,具体是否需要执行垃圾回收Java虚拟机会自行判断。
  • 可以通过添加参数查看类加载卸载的日志

堆回收

垃圾回收的两个大阶段:

  1. 找垃圾,判定垃圾。
  2. 释放垃圾。

判断垃圾方法

1.引用计数器

就是针对每个对象,都会额外引入一小块内存,保存这个对象有多少个引用指向它。

引用计数法的优点是实现简单,C++中的智能指针就采用了引用计数法,但是它也存在缺点,主要有两点:

  • 每次引用和取消引用都需要维护计数器,对系统性能会有一定的影响
  • 存在循环引用问题,所谓循环引用就是当A引用B,B同时引用A时会出现对象无法回收的问题。如下代码
class A{
A a;
}
a1=new A();
a2=new A();
a1.a=a2;
a2.a=a1;
a1=null;
a2=null;

2.可达性分析

Java使用的是可达性分析算法来判断对象是否可以被回收。可达性分析将对象分为两类:垃圾回收的根对象(GCRoot)和普通对象,对象与对象之间存在引用关系。

如图:e f 未跟root建立可达关系,所以ef是垃圾

以下对象是GC Root对象

a)栈上的局部变量
b)常量池中的引用指向的对象
c)方法区中的家庭成员指向的对象

回收垃圾算法

1.标记清除法

标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出所有存活对象。
清除阶段,从内存中删除没有被标记也就是非存活对象。

回收前

回收后

优点:

实现简单,只需要在第一阶段给每个对象维护标志位,第二阶段删除对象即可。

缺点:

1.碎片化问题
由于内存是连续的,所以在对象被删除之后,内存中会出现很多细小的可用内存单元。如果我们需要的是一个比较大的空间,很有可能这些内存单元的大小过小无法进行分配。

2.分配速度慢。由于内存碎片的存在,需要维护一个空闲链表,极有可能发生每次需要遍历到链表的最后才 能获得合适的内存空间。

2.复制算法

1.准备两块空间from和to。

2.对象首先放入from空间

3.垃圾回收后,存活对象放入to空间

4.将两块空间名字互换

优点:

吞吐量高
复制算法只需要遍历一次存活对象复制到To空间即可,比标记-整理算法少了一次遍历的过程,因而性能较好,但是不如标记-清除算法,因为标记清除算法不需要进行对象的移动

不会发生碎片化

复制算法在复制之后就会将对象按顺序放入To空间中,所以对象以外的区域都是可
用空间,不存在碎片化内存空间。

缺点:

内存使用效率低

每次只能让一半的内存空间来为建对象使用

3.标记整理算法

1.标记阶段,将所有存活的对象进行标记。Java中使用可达性分析算法,从GC Root开始通过引用链遍历出所有存活对象。
2.整理阶段,将存活对象移动到堆的一端。清理掉存活对象的内存空间。

优点:

1.内存使用效率高

整个堆内存都可以使用,不会像复制算法只能使用半个堆内存

2.不会发生碎片化

在整理阶段可以将对象往内存的一侧进行移动,剩下的空间都是可以分配对象的有效空间

缺点:

整理效率不高 

4.分代GC

分代垃圾回收会将上面几个算法组合使用。

分代垃圾回收将整个内存区域分为年轻代老年代,老年代存放存货时间比较长的对象。年轻代又划分成了伊甸园区和幸存者区。幸存者区又分为两块区域,用来实现复制算法,我们称为s0和s1 

1.首先创建出的对象会放入伊甸园区

2.伊甸园区满了,就会触发一次年轻代的垃圾回收,称为Minor GC,会用复制算法将伊甸园区和From需要回收的对象回收,把没有回收的对象放入To区。

3.继续往伊甸园区放入对象,当伊甸园区满了之后继续触发2流程,每次Minor GC都会为对象记录他的年龄,初始值为0,每次GC完加1。如果年龄达到阈值,对象会被晋升为老年代。 

4.当老年代中空间不足,无法放入新的对象时,先尝试minor gc如果还是不足,就会触发Full GC,Full GC会对整个堆进行垃圾回收。如果Full GC依然无法回收掉老年代的对象,那么当对象继续放入老年代时,就会抛出Out Of Memory异常。

垃圾回收器的实现

垃圾回收器是垃圾回收算法的具体实现。
由于垃圾回收器分为年轻代和老年代,除了G1之外其他垃圾回收器必须成对组合进行使用。

1.Serial 收集器(新生代)/ Serial Old 收集器(老年代)jvm配置参数:-XX:+UseSerialGC 新生代、老年代都使用串行回收器。

这俩都是串行收集,Serial使用的是复制算法,Seral Old使用的是标记整理算法。在进行垃圾扫描和释放的时候,业务线程要停止工作。就是这边停止工作,他先扫描完,再去进行释放,然后业务线再继续工作。这种方式扫描的慢,释放的也慢,也会产生严重的 STW 问题。

2.ParNew 收集器(年轻代)

使用的是复制算法,JVM 配置参数: -XX:+UseParNewGC 新生代使用ParNew回收器,老年代使用串行回收器。

这个回收器是并发收集的,引入了多线程,Parallel Scavenge 比 ParNew 多出了一些参数,可以用来控制 STW 的时间

3.CMS垃圾回收器(老年代)

标记清除算法,参数:XX:+UseConcMarkSweepGC

执行步骤:

1.初始标记,用极短的时间标记出GC Roots能直接关联到的对象。
2.并发标记,标记所有的对象,用户线程不需要暂停。
3.重新标记,由于并发标记阶段有些对象会发生了变化,存在错标、漏标等情况,需要重新标记。
4.并发清理,清理死亡的对象,用户线程不需要暂停。

缺点:

1.CMS使用了标记-清除算法,在垃圾收集结束之后会出现大量的内存碎片,CMS会在Full GC时进行碎片的整理。这样会导致用户线程暂停,可以使用-XX:CMSFullGCsBeforeCompaction=N参数(默认0)调整N次Full GC之后再整理。
2.无法处理在并发清理过程中产生的“浮动垃圾”,不能做到完全的垃圾回收。
3.如果老年代内存不足无法分配对象,CMS就会退化成Serial Old单线程回收老年代。

4.Parallel Scavenge垃圾回收器(年轻代 )

最大暂停时间

-XX:MaxGCPauseMillis=n

设置每次垃圾回收时的最大停顿毫秒数

吞吐量
-XX:GCTimeRatio=n
设置吞吐量为n(用户线程执行时间=n/n+1)

自动调整内存大小
-XX:+UseAdaptiveSizePolicyi
可以让垃圾回收器根据吞吐量和最大停顿的毫秒数自动调整内存大小

复制算法,这个回收器是并发收集的,引入了多线程,Parallel Scavenge 比 ParNew 多出了一个参数,可以用来控制 STW 的时间

优点
吞吐量高,而且手动可控。为了提高吞吐量,虚拟机会动态调整堆的参数

缺点
不能保证单次的停顿时间

适用场景
后台任务,不需要与用户交互,并且容易产生大量的对象比如:大数据的处理,大文件导出

5.Parallel Old垃圾回收器(老年代)

Parallel Old是为Parallel Scavenge收集器设计的老年代版本,利用多线程并发收集。参数 :- XX:+UseParallelGC 或-XX:+UseParallelOldGC可以使用Parallel Scavenge+Parallel Old这种组合。

优点
并发收集,在多核CPU下效率较高

缺点
暂停时间会比较长

6.G1垃圾回收器 

参数1 :- XX:+UseG1GC 打开G1的开关,
JDK9之后默认不需要打开
参数2 :- XX:MaxGCPauseMillis=毫秒值
最大暂停的时间

JDK9之后默认的垃圾回收器是G1(Garbage First)垃圾回收器。
Parallel Scavenge关注吞吐量,允许用户设置最大暂停时间,但是会减少年轻代可用空间的大小CMS关注暂停时间,但是吞吐量方面会下降。而G1设计目标就是将上述两种垃圾回收器的优点融合:
1.支持巨大的堆空间回收,并有较高的吞吐量。
2.支持多CPU并行垃圾回收。
3.允许用户设置最大暂停时间。

JDK9之后强烈建议使用G1垃圾回收器。

G1的整个堆会被划分成多个大小相等的区域,称之为区Region,区域不要求是连续的。分为Eden、Survivor、Old区。Region的大小通过堆空间大小/2048计算得到,也可以通过参数

-XX:G1HeapRegionSize=32m指定(其中32m指定region大小为32M),Region size必须是2的指数幂,取值范围从1M到32M。

G1回收器有两种方式

1.年轻代回收2.混合回收

年轻代回收(Young GC),回收Eden区和Survivor区中不用的对象。会导致STW,G1中可以通过参数-XX:MaxGCPauseMillis=n(默认200) 设置每次垃圾回收时的最大暂停时间毫秒数,G1垃圾回收器会尽可能地保证暂停时间。

执行流程

1、新创建的对象会存放在Eden区。当G1判断年轻代区不足(max默认60%),无法分配对象时需要回收时会执行Young GC.
2、标记出Eden和Survivor区域中的存活对象,
3、根据配置的最大暂停时间选择某些区域将存活对象复制到一个新的Survivor区中(年龄+1),清空这些区域。

4、后续Young GC时与之前相同,只不过Survivor区中存活对象会被搬运到另一个Survivor区。
5、当某个存活对象的年龄到达阈值(默认15),将被放入老年代。

6、部分对象如果大小超过Region的一半,会直接放入老年代,这类老年代被称为Humongous区。比如堆内存是4G,每个Region是2M,只要一个大对象超过了1M就被放入Humongous区,如果对象过大会横跨多个Region。

7、多次回收之后,会出现很多Old老年代区,此时总堆占有率达到阈值时(-XX:InitiatingHeapOccupancyPercent默认45%)会触发混合回收MixedGC。回收所有年轻代和部分老年代的对象以及大对象区。采用复制算法来完成。 

注意:如果清理过程中发现没有足够的空Region存放转移的对象,会出现Full GC。单线程执行标记-整理算法,此时会导致用户线程的暂停。所以尽量保证应该用的堆内存有一定多余的空间。

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

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

相关文章

java中大型医院HIS系统源码 Angular+Nginx+SpringBoot云HIS运维平台源码

java中大型医院HIS系统源码 AngularNginxSpringBoot云HIS运维平台源码 云HIS系统是一款满足基层医院各类业务需要的健康云产品。该产品能帮助基层医院完成日常各类业务,提供病患预约挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生工作站和护士工…

MySQL-排序与分页

1. 排序 如果没有使用排序操作,默认情况下查询返回的数据是按照添加数据的顺序显示的。 SELECT * FROM employees;1.1 基本使用 1)使用 ORDER BY 对查询到的数据进行排序操作。 升序:ASC(ascend)降序:DESC (descend) 练习&am…

使用 LLMLingua-2 压缩 GPT-4 和 Claude 提示

原文地址:Compress GPT-4 and Claude prompts with LLMLingua-2 2024 年 4 月 1 日 向大型语言模型(LLM)发送的提示长度越短,推理速度就会越快,成本也会越低。因此,提示压缩已经成为LLM研究的热门领域。 …

JVM基础:类的生命周期详解

JDK版本:jdk8 IDEA版本:IntelliJ IDEA 2022.1.3 文章目录 一. 生命周期概述二. 加载阶段(Loading)2.1 加载步骤2.2 查看内存中的对象 三. 连接阶段(Linking)3.1 连接之验证3.2 连接之准备3.3 连接阶段之解析 四. 初始化阶段(Initialization)4.1 单个类的…

ChatGPT(3.5版本)开放无需注册:算力背后的数据之战悄然打响

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

Logback日志框架(超详细)

logback-classic-1.2.3.jarhttp://链接: https://pan.baidu.com/s/1cA3gVB_6DEA-cSFJN6MDGw 提取码: sn8i 复制这段内容后打开百度网盘手机App,操作更方便哦 logback-core-1.2.3.jarhttp://链接: https://pan.baidu.com/s/19eCsvsO72a9PTqpXvXxrgg 提取码: 5yp…

元宇宙虚拟空间的场景构造(二)

前言 该文章主要讲元宇宙虚拟空间的场景构造,基本核心技术点,不多说,直接引入正题。 场景的构造 使用引入的天空模块 this.sky new Sky(this); 在Sky模块里,有设置对其中的阳光进行不同时间段的光线处理。而天空又是怎么样的…

微软云学习环境

微软公有云 - Microsoft Azure 本文介绍通过微软学习中心Microsoft Learn来免费试用Azure上的服务,也不需要绑定信用卡。不过每天只有几个小时的时间。 官网 https://docs.microsoft.com/zh-cn/learn/ 实践 比如创建虚拟机,看到自己的账号下多了Learn的…

非关系型数据库-----------探索 Redis高可用 、持久化、性能管理

目录 一、Redis 高可用 1.1什么是高可用 1.2Redis的高可用技术 二、 Redis 持久化 2.1持久化的功能 2.2Redis 提供两种方式进行持久化 三、Redis 持久化之----------RDB 3.1触发条件 3.1.1手动触发 3.1.2自动触发 3.1.3其他自动触发机制 3.2执行流程 3.3启动时加载…

机器学习KNN最邻近分类算法

文章目录 1、KNN算法简介2、KNN算法实现2.1、调用scikit-learn库中KNN算法 3、使用scikit-learn库生成数据集3.1、自定义函数划分数据集3.2、使用scikit-learn库划分数据集 4、使用scikit-learn库对鸢尾花数据集进行分类5、什么是超参数5.1、实现寻找超参数5.2、使用scikit-lea…

下载页面上的视频

引言:有些页面上的视频可以直接右键另存为或者F12检索元素找到视频地址打开后保存,但有些视频页面是转码后的视频,不能直接另存为视频格式,可以参考下本方法 以该页面视频为例:加载中...点击查看详情https://wx.vzan.c…

【Node.js从基础到高级运用】二十一、使用child_process模块创建子进程

引言 在Node.js中,child_process模块是一个提供了创建和管理子进程的能力的核心模块。通过使用child_process模块,Node.js可以执行系统命令、运行其他脚本或应用程序,实现与Node.js进程的并行处理。 child_process模块提供了几种创建子进程的…

【C++】vector模拟实现

目录 简介:私有成员:迭代器: 无参构造函数:push_back:reserve:resize:push_back: operator[]重载:begin && end:size && capacity:insert:erase:带参构造…

matlab使用教程(35)—求解时滞微分方程(3)

1中立型 DDE 以下示例说明如何使用 ddensd 求解中立型 DDE(时滞微分方程),其中时滞出现在导数项中。此问题最初由 Paul [1] 提出。方程是: 由于该方程在 y ′ 项中存在时滞,因此该方程称为中立型 DDE。如果时滞仅出现…

Python 与机器学习,在服务器使用过程中,常用的 Linux 命令包括哪些?

🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 本博客旨在分享在实际开发过程中,开发者需要了解并熟练运用的 Linux 操作系统常用命令。Linux 作为一种操作系统,与 Windows 或 MacOS 并驾齐驱,尤其在服务器和开发环…

使用 RisingWave、NATS JetStream 和 Superset 进行实时物联网监控

在物联网(IoT)背景下,处理实时数据会遇到一些特定的障碍,如边缘计算资源不足、网络条件限制、扩展性存在问题、设备间有多样性差异。要克服这些挑战,需要高效的边缘计算技术、强大的安全措施、标准化协议、可扩展的管理…

spring中各种bean加载顺序

具体加载顺序按照罗列的顺序 XXXAware ApplicationContextAware、EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware 顾名思义,用于获取对应的对象,需要在实体类中声明对应的对象且当前类为普通类能被注入。 InitializingBean void afterProp…

【软件工程】测试规格

1. 引言 1.1简介 本次的测试用例是基于核心代码基本开发完毕,在第一代系统基本正常运行后编写的,主要目的是为了后续开发与维护的便利性。 该文档主要受众为该系统后续开发人员,并且在阅读此文档前最后先阅读本系统的需求文档、概要设计文…

日志、logback、logback.xml --java学习笔记

什么是日志? 好比生活中的日记,可以记录你生活中的点点滴滴程序中的日志,通常就是一个文件,里面记录的是程序运行过程中的各种信息 之前记录日志的方法都是使用输出语句: 这种方法其实并不适合用来记录日志&#xff…

【c++】初阶模版与STL简单介绍

🔥个人主页:Quitecoder 🔥专栏:c笔记仓 朋友们大家好,本篇文章介绍一下模版和对STL进行简单的介绍,后续我们进入对STL的学习! 目录 模版1.泛型编程2.函数模板2.1函数模板的原理2.2模版的实例化…