jvm题库详解

1、JVM内存模型

注意:这个是基于jdk1.8之前的虚拟机,在jdk1.8后 已经没有方法区,一并合并到堆中的元空间了

JVM内存区域总共分为两种类型

线程私有区域:程序计数器、本地方法栈和虚拟机栈
线程共享区域:堆(heap)和方法区

特征

线程私有区域:依赖用户的线程创建而创建、销毁而销毁,因用户每次访问都会独立开启一个线程,跟本地的线程相对应(用白话文讲就是同生共死或朝生夕死);
线程共享区域:它是随着虚拟机的开启而创建,关闭而销毁;

名词解释

程序计数器
用户每次访问都会独立开启一个线程,程序计数器会记录每次当前执行代码的行号指示器

本地方法栈

本地方法栈是用来区别虚拟机调用外部的执行方法,而本地方法栈则为Native修饰,那么该方法是一个C栈,Sun HotSpot将本地方法栈与虚拟机栈合二为一

堆(heap)

创建的数组和对象都放入java堆中,当然也是垃圾收集器重要回收的地方, VM主要采用分代收集算法,主要产生在新生代(Yong GC)(Eden 区From 和To)和 老年代

方法区

用来存储于类、运行常量池、静态的变量和编译编译后的代码等数据,java VM会把这些信息收集到方法区,即用java堆的永久代来实现方法区,这样就可以实现VM 像堆内存一样管理方法区的内存

2、JVM运行时内存分配

Java堆内存可以分为

新生代(Enden、SurvivorFrom和SurvivorTo)老年代、元空间
新生代与老年代默认比例是1:2
新生代中Enden SurvivorFrom SurvivorTo 默认比例是:8:1:1

新生代

是用来存放new的对象。一般占据堆的1/3空间。由于频繁创建对象,所以新生代会频繁触发MinorGC 进行垃圾回收。新生代又分为 Eden 区、ServivorFrom、ServivorTo 三个区。

Enden

用来存放新的对象出生地(当新创建对象很大时,会直接分配到老年代),当新生代内存不够时会触动MinorGc,会对新生产生垃圾回收

SurvivorFrom

上一次 GC 的幸存者,作为这一次 GC 的被扫描者

SurvivorTo

保留了一次 MinorGC 过程中的幸存者

采用的算法

MinorGC 的过程(复制->清空->互换)

复制算法执行流程

eden 和SurvivorFrom 复制到 SurvivorTo,年龄+1
首先,把 Eden和 SurvivorFrom区域中存活的对象复制到 SurvicorTo区域(如果有对象的年龄以及达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄+1(如果 ServicorTo 够位置了就放到老年区);
清空 Eden 和 ServicorFrom 中的对象;
ServicorTo 和 ServicorFrom 互换,原 ServicorTo 成为下一次 GC 时的 ServicorFrom区。

老年代

主要存放应用程序中生命周期长的内存对象。
老年代的对象比较稳定,所以 MajorGC 不会频繁执行。在进行 MajorGC 前一般都先进行
了一次 MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次 MajorGC 进行垃圾回收腾出空间。
MajorGC 采用标记清除算法:首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象。MajorGC 的耗时比较长,因为要扫描再回收。MajorGC 会产生内存碎片,为了减少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。当老年代也满了装不下的时候,就会抛出 OOM(Out of Memory)异常。

永久代

指内存的永久保存区域,主要存放 Class 和 Meta(元数据)的信息,Class 在被加载的时候被放入永久区域,它和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的 Class 的增多而胀满,最终抛出 OOM 异常。

JAVA8 与元数据

在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入 native memory, 字符串池和类的静态变量放入 java 堆中,这样可以加载多少类的元数据就不再由MaxPermSize 控制, 而由系统的实际可用空间来控制。

3、如何确定当前对象是个垃圾

引用计数法

在 Java 中,引用和对象是有关联的。如果要操作对象则必须用引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说,即一个对象如果没有任何与之关联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么个对象就是可回收对象。

相互引用的时候,内存不能回收

所谓引用计数法,每个对象额外保存一个计数属性,如果有一个对象引用了它,那么该属性会加1,例,

A a = new A();
A a2 = a;

上面这段代码会在堆中生成一个A的对象实例,且a、a2都指向了该对象,那么该对象的计数属性便是2,又如,

A a = new A();
A a2 = a;
a = null;
a2 = null;

这时a、a2均指向了null,那么A的对象实例的计数属性则为0,按照引用计数法的定义这时该实例可以被回收。

A a = new A();
B b = new B();
a.b = b;
b.a = a;
a = null;
b = null;

上面的代码在堆中会有一个A的实例一个B的实例,且计数属性均为1,执行了第3、4两行代码后,两个实例的引用计数均为2,执行了5、6两行代码后两个实例的计数属性均为1,这时a、b均指向了null,但是堆中的两个实例的计数属性的值却不为0,那么这两个实例无法回收,存在内存泄漏的风险;

可达性分析

为了解决引用计数法的循环引用问题,Java 使用了可达性分析的方法。通过一系列的“GC roots”对象作为起点搜索。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。

4、GCrooot 包括哪些?

虚拟机栈(栈桢中的局部变量表操作数栈)中的引用的对象
方法区中的类静态属性引用的对象
方法区中的常量引用的对象
本地方法栈中JNI的引用的对象

5、JVM对象头包含哪些部分

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对⻬填充(Padding)
对象头
实例数据
对⻬填充

给定⼀个具体的类,请分析对象的内存占用!

每个long类型的字段占⽤8字节,3个long字段占⽤24字节。byte 字段占⽤1个字节。

6、GC算法有哪些

标记清除算法( Mark-Sweep )
分为两个阶段,标注和清除。标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。如图

从图中我们就可以发现,该算法最大的问题是:内存碎片化严重,效率低后续可能发生大对象不能找到可利用空间的问题

复制算法( copying )
按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉,如图:

这种算法虽然实现简单,内存效率高,不易产生碎片,但是最大的问题是:可用内存被压缩到了原本的一半。且存活对象增多的话,Copying 算法的效率会大大降低。

标记整理算法(Mark-Compact)
结合了以上两个算法,为了避免缺陷而提出。标记阶段和 Mark-Sweep 算法相同,标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象。如图:

7、JVM中类的加载机制

1)加载→验证→准备→解析→初始化
加载
加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的入口;
2) 验证
确保这个类符合要求
3) 准备
加载一些静态变量和常量
4) 解析
把编译class文件进行解析
5)初始化
初始化默认对象属性信息
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/chuige2013/article/details/129654375

8、分代收集算法
分代收集法是目前大部分 JVM 所采用的方法,其核心思想是根据对象存活的不同生命周期将内存划分为不同的域,一般情况下将 GC 堆划分为老生代(Tenured/Old Generation)和新生代(YoungGeneration)。老年代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法。

新生代采用复制算法
目前大部分 JVM 的 GC 对于新生代都采取 Copying 算法,因为新生代中每次垃圾回收都需要频繁回收对象,即要复制的操作比较少,但通常并不是按照 1:1 来划分新生代。一般将新生代划分为一块较大的 Eden 空间和两个较小的 Survivor 空间(From Space, To Space),每次使用 Eden 空间和其中的一块Survivor 空间,当进行回收时,将该两块空间中还存活的对象复制到另一块 Survivor 空间中。

老年代采用复制算法
而老年代因为每次只回收少量对象,因而采用 Mark-Compact 算法。
当对象在 Survivor 区躲过一次 GC 后,其年龄就会+1。默认情况下年龄到达 15 的对象会被移到老生代中。

9、JDK1.8 和 1.7做了哪些优化
在 Java8 中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入 native memory, 字符串池和类的静态变量放入 java 堆中,这样可以加载多少类的元数据就不再由MaxPermSize 控制, 而由系统的实际可用空间来控制。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/chuige2013/article/details/129654375

10、内存泄漏和内存溢出有什么区别
Csdn : JAVA内存泄漏和内存溢出的区别和联系_马帅的博客的博客-CSDN博客_java内存泄漏和内存溢出

内存泄漏 memory leak
是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。

内存溢出 out of memory
指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。

二者的关系
内存泄漏的堆积最终会导致内存溢出
内存溢出:就是你要的内存空间超过了系统实际分配给你的空间,此时系统相当于没法满足你的需求,就会报内存溢出的错误。
内存泄漏:是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。就相当于你租了个带钥匙的柜子,你存完东西之后把柜子锁上之后,把钥匙丢了或者没有将钥匙还回去,那么结果就是这个柜子将无法供给任何人使用,也无法被垃圾回收器回收,因为找不到他的任何信息。
内存溢出:一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出。比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出。说白了就是我承受不了那么多,那我就报错

内存泄漏的分类(按发生方式来分类)
常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。

偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。

隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

内存溢出的原因及解决方法:
内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
代码中存在死循环或循环产生过多重复的对象实体;
使用的第三方软件中的BUG;
启动参数内存值设定的过小

内存溢出的解决方案:
第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。

重点排查以下几点:
检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
检查代码中是否有死循环或递归调用。
检查是否有大循环重复产生新对象实体。
检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/chuige2013/article/details/129654375

11、JVM中栈上分配和内存逃逸解释
栈上分配:就是把没发生逃逸的对象,在栈帧分配空间。(一般对象分配空间是在堆)逃逸
逃逸分析(个人理解):就是方法内的对象,可以被方法外所访问
栈上分配:就是把没发生逃逸的对象,在栈分配空间。(一般对象分配空间是在堆)逃逸

二者联系:jvm根据对象是否发生逃逸,会分配到不同(堆或栈)的存储空间。
如果对象发生逃逸,那会分配到堆中。(因为对象发生了逃逸,就代表这个对象可以被外部访问,换句话说,就是可以共享,能共享数据的,无非就是堆或方法区,这里就是堆。)

如果对象没发生逃逸,那会分配到栈中。(因为对象没发生逃逸,那就代表这个对象不能被外部访问,换句话说,就是不可共享,这里就是栈。)
那我们再想深一层,为什么会有逃逸分析,有栈上分配这些东西?
当然是为了主体的考虑,主体就是jvm,或者直接说为了GC考虑也不为过。大家想想,GC主要回收的对象是堆和方法区。GC不会对栈、程序计数器这些进行回收的,因为没东西可以回收。

12、如何定位CPU100%占用

Linux 命令使用 top命令

执⾏top -p 2732单独监控该进程
在第2步的监控界⾯输⼊H,获取当前进程下的所有线程信息

找到消耗cpu特别⾼的线程编号(假设是2734)

执⾏jstack 2732对当前的进程做dump,输出所有的线程信息
同时将第4步得到的线程⼗进制编号2734转成16进制(AAE),在堆栈信息⾥⾯去找对应线程内容

13、在程序中如何判断是否有内存泄漏

内存泄漏的特点:
对象一直被引用,GC不能被回收,导致内存泄漏,一直内存泄露没有问题,多次内存泄露可能会引起内存溢出
dump 工具进行离线分析

14、JVM参数调优

Xmx 最大堆内存配置 -Xmx=2G
-Xms 最小堆内存配置 -Xms=2G
最大堆内存和最小堆内存要配置一样,不然会动态扩容 缩容

15、JVM运行区域分为几块,作用是什么
线程共享:
堆:new 对象和数组,栈上分配对象
方法区 :class对象、静态变量 常量池

线程私有:
程序计数器:某一个线程执行的行号位置
本地方法栈:调用外部方法 native 关键词修饰的 变量
虚拟机栈:每一个方法属于一个栈帧,而栈帧里面包括

栈帧
局部变量表
操作数栈
动态链接
返回值

16、GC算法有哪些,收集器有哪些
引用计数法
可达性分析
复制算法
分代算法
标记算法
标记整理算法

收集器:
Serial 串联
parNew 多线程
Parallel Scavenge 并发变

cms 四个阶段
初始标记:
并发标记:
重新标记:
并发删除:

17、MiniGC 怎样扭转到MajorGC 里面

Age = 15
空间担保:新生代空间不够时
大对象直接分配到老年代

18、JVM中类加装机制
类加载器
虚拟机设计团队把加载动作放到 JVM 外部实现,以便让应用程序决定如何获取所需的类,JVM 提供了 3 种类加载器:
启动类加载器(Bootstrap ClassLoader)
负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath 参数指定路径中的,且被虚拟机认可(按文件名识别,如 rt.jar)的类。

扩展类加载器(Extension ClassLoader)
负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类库。

应用程序类加载器(Application ClassLoader):
负责加载用户路径(classpath)上的类库。
JVM 通过双亲委派模型进行类的加载,当然我们也可以通过继承 java.lang.ClassLoader 实现自定义的类加载器。

JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程。

18.1、加载
加载是类加载过程中的一个阶段,这个阶段会在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的入口。注意这里不一定非得要从一个 Class 文件获取,这里既可以从 ZIP 包中读取(比如从 jar 包和 war 包中读取),也可以在运行时计算生成(动态代理),也可以由其它文件生成(比如将 JSP 文件转换成对应的 Class 类)。

18.2、验证
这一阶段的主要目的是为了确保 Class 文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

18.3、准备
准备阶段是正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配这些变量所使用的内存空间。注意这里所说的初始值概念,比如一个类变量定义为:

public static int v = 8080;

实际上变量 v 在准备阶段过后的初始值为 0 而不是 8080,将 v 赋值为 8080 的 put static 指令是程序被编译后,存放于类构造器方法之中。
但是注意如果声明为:
public static final int v = 8080;
在编译阶段会为 v 生成 ConstantValue 属性,在准备阶段虚拟机会根据 ConstantValue 属性将 v赋值为 8080。

18.4、解析
解析阶段是指虚拟机将常量池中的符号引用替换为直接引用的过程。符号引用就是 class 文件中的:
CONSTANT_Class_info
CONSTANT_Field_info
CONSTANT_Method_info
等类型的常量。
1)符号引用
符号引用与虚拟机实现的布局无关,引用的目标并不一定要已经加载到内存中。各种虚拟机实现的内存布局可以各不相同,但是它们能接受的符号引用必须是一致的,因为符号引用的字面量形式明确定义在 Java 虚拟机规范的 Class 文件格式中。
2)直接引用
直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。如果有了直接引用,那引用的目标必定已经在内存中存在。

18.5、初始化
初始化阶段是类加载最后一个阶段,前面的类加载阶段之后,除了在加载阶段可以自定义类加载器以外,其它操作都由 JVM 主导。到了初始阶段,才开始真正执行类中定义的 Java 程序代码。
类构造器
初始化阶段是执行类构造器方法的过程。方法是由编译器自动收集类中的类变
量的赋值操作和静态语句块中的语句合并而成的。虚拟机会保证子方法执行之前,父类
的方法已经执行完毕,如果一个类中没有对静态变量赋值也没有静态语句块,那么编译
器可以不为这个类生成()方法。

注意以下几种情况不会执行类初始化:
通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。

18.5.1、通过子类引用父类的静态字段
只会触发父类的初始化,而不会触发子类的初始化。子类和父类都会被加载。

public class B {
    public static int b = 10;
    static {
        System.out.println("B初始化");
    }
}
public class A extends B{
    static {
        System.out.println("A初始化");
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println(A.b);
    }
}
输出:
B初始化
10
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B
me.ffulauh.javalang.jvm.classinitdemo.A

18.5.2、定义对象数组

不会触发该类的初始化。

B[] bs=new B[10];
输出:
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B

18.5.3、常量

常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。
public static final int NUM = new Random().randomInt();
调用上述常量就会触发类的初始化

public class Consts {
    public static final String HAN="CaptHua";
    static {
        System.out.println("Consts初始化");
    }
}
public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        System.out.println(Consts.HAN);
        printLoadedClass(null);
    }
}
输出:
CaptHua
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test

public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        System.out.println(Consts.NUM);
        printLoadedClass(null);
    }
}
输出:
Consts初始化
625281582
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.Consts
 

18.5.4、通过类名获取 Class 对象
不会触发类的初始化,会加载。
通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。通过 ClassLoader 默认的 loadClass 方法,也不会触发初始化动作。

public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        System.out.println(B.class);
        printLoadedClass(null);
    }
}
输出:
class me.ffulauh.javalang.jvm.classinitdemo.B
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B

18.5.5、通过 Class.forName 加载指定类时

如果指定参数 initialize 为 false 时,也不会触
发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。会加载类

public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        Class.forName("me.ffulauh.javalang.jvm.classinitdemo.B",false,Thread.currentThread().getContextClassLoader());
        printLoadedClass(null);
    }
}
输出:
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B
 

18.5.6、通过 ClassLoader 默认的 loadClass 方法
 

public class Test extends PrintClassInfo{
    public static void main(String[] args) throws Exception{
        ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
        classLoader.loadClass("me.ffulauh.javalang.jvm.classinitdemo.B");
        printLoadedClass(null);
    }
}
输出:
加载的类:
me.ffulauh.javalang.jvm.classinitdemo.PrintClassInfo
me.ffulauh.javalang.jvm.classinitdemo.Test
me.ffulauh.javalang.jvm.classinitdemo.B
 

18、什么是双亲委派机制?
它有什么作用?
双亲委派机制的意思是除了顶层的启动类加载器以外,其余的类加载器,在加载之前,都会委派给它的
⽗加载器进⾏加载。这样⼀层层向上传递,直到祖先们都⽆法胜任,它才会真正的加载。
通过带有优先级的层级关可以避免类的重复加载;
保证 Java 程序安全稳定运⾏,Java 核⼼ API 定义类型不会被随意替换。

19、设置堆空间的最大值(-Xmx)
应该要考虑哪些因素?
需要根据系统的配置来确定,要给操作系统和JVM其他内存区域(栈、⽅法区)留下⼀定的剩余空间。
推荐配置系统或容器⾥可⽤内存的 70 %~80%最好。
假设物理内存是8G,设置多⼤堆内存⽐较合适?
系统有 8G 物理内存,系统⾃⼰可能会⽤掉⼀点,⼤概还有 7.5G 可以⽤。
那么建议配置-Xmx6g (7.5g*0.8=6g)

20、Java8默认使用的垃圾收集器是什么?

Java8版本的Hotspot JVM,默认情况下使用的是并行垃圾收集器(Parallel GC)。其他⼚商提供的JDK8基本上也默认使⽤并行垃圾收集器。
在这里插入图片描述

21、什么是并行垃圾收集?

并行垃圾收集,是指使⽤多个GC worker 线程并行地执行垃圾收集,能充分利用多核CPU的能力,缩短垃圾收集的暂停时间。
除了单线程的GC,其他的垃圾收集器,比如 PS,CMS, G1等新的垃圾收集器都使用了多个线程来并行执行GC⼯作

在这里插入图片描述

22、什么是STW?什么是安全点,什么是安全区域?

总结

23、CMS、G1垃圾回收器中的三色标记你了解吗?
三色标记法是⼀种垃圾回收法,它可以让 JVM 不发生或仅短时间发生 STW(Stop The World),从而达到清除 JVM 内存垃圾的目的。
三色标记法将对象的颜色分为了黑、灰、白三种颜⾊。
黑色:该对象已经被标记过了,且该对象下的属性也全部都被标记过了;
灰色:对象已经被垃圾收集器扫描过了,但是对象中还存在没有扫描的引用 ;
白色:表示对象没有被垃圾收集器访问过,即表示不可达;

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

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

相关文章

android MMKV数据持久化缓存集合

前言 最近在使用mmkv缓存的时候 发现没有集合缓存 非常不方便 自己写一个方法 MMKV public class MmkvUtils {private MmkvUtils() {throw new UnsupportedOperationException("u cant instantiate me...");}public static void init() {MMKV.initialize(LeoUtils…

脚本.py文件转.exe文件遇见的问题,打开exe文件出现弹窗: No module named ‘xxx‘

目录 1 问题2 问题分析3 解决过程3.1 确保Pillow库存在3.2 迷惑阶段3.3 解决问题 4 希望大佬解答 1 问题 今天做了一个使用Python写的脚本文件.py,打算把它转换成.exe文件。点击生成的exe文件时,出现了如下弹窗。 2 问题分析 根据错误描述&#xff1…

国际黄金在哪里买?

国际黄金可以在以下几个主要的市场和渠道进行购买: 1. 黄金交易所:国际上有多个黄金交易所,其中最知名的是伦敦金属交易所(London Bullion Market Association,简称LBMA)。LBMA是全球最大的黄金交易市场&am…

Arrays --Java学习笔记

Arrays 用来操作数组的一个工具类 Arrays类提供的常见方法: 代码演示: import java.util.Arrays; import java.util.function.IntToDoubleFunction; import java.util.function.IntUnaryOperator;public class Arrays类 {public static void main(Str…

[JAVAEE]—进程和多线程的认识

文章目录 什么是线程什么是进程进程的组成什么是pcb 进程概括线程线程与进程的关系线程的特点 创建线程创建线程方法创建线程的第二种方法对比 其他的方式匿名内部类创建线程匿名内部类创建Runable的子类lambda表达式创建一个线程 多线程的优势 什么是线程 什么是进程 首先想…

OpenCASCADE开发指南<七>:OCC 中的数学基本类型和数学算法

1 标准对象的集合容器 在处理现实问题时,经常将问题抽象成一个数学模型,接着对模型求解, 然后将解提取出来以解决现实问题。 其实在 CAD 软件中, 主要解决的就是数学模型。因此,本节将描述 OCC 的数学基本类型和数学算…

JavaWeb06-MVC和三层架构

目录 一、MVC模式 1.概述 2.好处 二、三层架构 1.概述 三、MVC与三层架构 四、练习 一、MVC模式 1.概述 MVC是一种分层开发的模式,其中 M:Model,业务模型,处理业务 V: View,视图,界面展…

【LeetCode每日一题】2789. 合并后数组中的最大元素

文章目录 [2789. 合并后数组中的最大元素](https://leetcode.cn/problems/largest-element-in-an-array-after-merge-operations/)思虑&#xff1a;代码&#xff1a; 2789. 合并后数组中的最大元素 思虑&#xff1a; 1.因为要合并的条件之一是&#xff0c;num[i]<num[i1].所…

5.Python从入门到精通—Python 运算符

5.Python从入门到精通—Python 运算符 Python 运算符算术运算符比较&#xff08;关系&#xff09;运算符赋值运算符逻辑运算符位运算符成员运算符身份运算符运算符优先级 Python 运算符 Python语言支持以下类型的运算符: 算术运算符比较&#xff08;关系&#xff09;运算符赋…

c++11语法特性

c11 1.c11发展简介 ​ 第一个比较正式的c标准是1998提出的c98标准。之后定了5年计划&#xff0c;每5年来一次大更新。在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。不过由于C03(TC1)主要是对C…

RabbitMQ 模拟实现【三】:存储设计

文章目录 数据库设计SQLite配置数据库实现 数据库关于哈希表等复杂类的存储启动数据库 文件设计消息持久化消息属性格式核心方法消息序列化消息文件回收 统一硬盘存储管理内存存储管理线程安全数据结构实现 数据库设计 数据库主要存储交换机、队列、绑定 SQLite 此处考虑的是…

完整的通过git命令框和windows窗口将本地文件上传到gitee远程仓库流程步骤

1.下载git 这个网站搜索git官方&#xff0c;去下载就行了 2.打开git安装后的Git Bash命令框 3.在Git Bash命令框设置一下要远程链接的gitee账号 git config --global user.name “名字”Git config --global user.email “邮箱” 4.查看一下账号设置 git config --global -…

Chitosan-PEG-DSPE 壳聚糖修聚乙二醇磷脂 DSPE-PEG-Chitosan

产品简称&#xff1a;DSPE-PEG-Chitosan、Chitosan-PEG-DSPE、DSPE-PEG-CS、CS-PEG-DSPE 产品中文名称&#xff1a;壳聚糖-聚乙二醇-磷脂、磷脂-聚乙二醇-壳聚糖 分子量&#xff1a;可以根据要求定制 保存条件&#xff1a; -20干燥保存 有效期&#xff1a; 一年 纯度&…

创建SpringCloudGateWay

创建SpringCloudGateWay 本案例基于尚硅谷《谷粒商城》项目&#xff0c;视频27 创建测试API网关 1、创建module 2、引入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:x…

C++进阶--mep和set的模拟实现

红黑树链接入口 底层容器 模拟实现set和map时常用的底层容器是红黑树。 红黑树是一种自平衡的搜索二叉树&#xff0c;通过对节点进行颜色标记来保持平衡。 在模拟实现set和map时&#xff0c;可以使用红黑树来按照元素的大小自动排序&#xff0c;并且保持插入和删除操作的高效…

Set cancelled by MemoryScratchSinkOperator

Bug信息 Caused by: com.starrocks.connector.spark.exception.StarrocksInternalException: StarRocks server StarRocks BE{host=10.9.14.39, port=9060} internal failed, status code [CANCELLED] error message is [Set cancelled by MemoryScratchSinkOperator]Bug产生的…

微信名【无感】的同学,你还好吗?

今天遇到个选择了微信一对一服务的同学&#xff0c;问Python问题&#xff0c;问题比较简单。 回答完问题&#xff0c;我就说了一句&#xff1a;问题比较简单&#xff0c;随意打赏一个红包就行了。 然后我就被拉黑了&#xff0c;然后我的解答问题&#xff0c;收到了一堆投诉&…

深入解析Java中锁机制以及底层原理

一、概述 1.1 背景 概念&#xff1a;锁是多线程编程中的机制&#xff0c;用于控制对共享资源的访问。可以防止多个线程同时修改或读取共享资源&#xff0c;从而保证线程安全。 作用&#xff1a;锁用于实现线程间的互斥和协调&#xff0c;确保在多线程环境下对共享资源的访问顺…

Flutter开发入门——Widget和常用组件

1.什么是Widget&#xff1f; 在Flutter中几乎所有的对象都是一个 widget 。与原生开发中“控件”不同的是&#xff0c;Flutter 中的 widget 的概念更广泛&#xff0c;它不仅可以表示UI元素&#xff0c;也可以表示一些功能性的组件如&#xff1a;用于手势检测的 GestureDetecto…