【JVM之再阅读】

发布时间:2024年01月09日

之前又一遍文章【深入学习Java虚拟机】不大完整:[https://blog.csdn.net/Tony666688888/article/details/135466362]请结合这篇在仔细研读一下:

首先我们带着这几个额问题来读这篇文章,可能收获会更大哦

1.请你谈谈你对JVM的理解?java8虚拟机和之前的变化更新?

2.什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?

3.JVM的常用调优参数有哪些?

4.内存快照如何抓取,怎么分析Dump文件?知道吗?

5.谈谈在JVM中,你对类加载器的认识?

1.类的加载,连接(验证、准备、解析)与初始化。

类的加载指的是将类的 .class 文件中的耳机子数据读入到内存中,将其放在运行时数据去的方法区内,然后再兑取创建一个java.lang.Class 对象,用来封装类在方法区内的数据结构。

1.ClassLoader(类加载器)

2.JVM提供了三总类加载器

1)根类加载器(使用C++编写,程序员无法在Java代码中或得该类)

2)扩展加载器,使用Java代码实现

3)系统加载器(应用加载器),使用java代码实现

3.用户自定义的类加载器

? java.lang.ClassLoader的子类

? 用户可以定制类的加载方式

4.程序中对子类的“主动使用”会导致父类被出释怀;但对父类的“主动”使用并不会导致子类的初始化

5.主动使用(六种

– 创建类的实例

– 访问某个类或接口的静态变量,或者对该静态变量赋值

– 调用类的静态方法

– 反射(如Class.forName(“com.itgwl.Test”)

– 初始化一个类的子类

– Java虚拟机启动时被标明为启动类的类(Java Test)

? 除了以上六种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化

6.父子加载器并非继承关系,也就是说子加载器不一定是继承父加载器。

1.JVM的位置

2.JVM的体系结构

3.类加载器

4.双亲委派机制

5.沙箱安全机制

6.Native

7.PC寄存器

8.方法区

9.栈

10.三种JVM

11.堆

12.新生区、 老年区

13.永久区

14.堆内存调优

15.GC 垃圾回收机制 (常用算法)

16.JMM

17.总结

一、 组成沙箱的基本组件:

1.字节码校验器:会

2.类装载器:

? 它防止恶意代码去干涉善意的代码; //加载器双亲委派机制(为了安全)

? 它守护了被新人的类库边界;

? 它将代码归入保护域,确定了代码可以进行哪些操作。

PC寄存器:每个线程都有一个程序计数器,是线程私有的,就是一个指针。

方法区:(static, final,Class,常量池)方法区是被所有的线程共享,此区域属于共享区间,静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关。

为什么main()先执行,最后结束~

栈:栈内存,主管安程序的运行,生命周期和线程同步;

线程结束,栈内存也就释放,对于栈来说,不存在垃圾回收问题。

一旦线程结束,栈就Over!

栈:8大基本类型 + 对象引用 + 实例的方法

栈运行原理:栈帧( 父帧、子帧)

栈满了:StackOverflowError

栈+堆+方法区:交互关系

三种JVM

1.Sun公司 HotSpot? 64-bit Server VM(目前我们所用的就是这个版本)

2.BEA JRockit

3.IMB J9 VM

Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。

类加载器读取了类文件后,一般会把什么东西放到堆中?类,方法,常量,变量~保存我们所有引用类型的真实对象;

堆内存中分为三个区域:

新生区(伊甸园区) Young/New

养老区 old

永久区 Perm

GC垃圾回收,主要是在伊甸园区和养老区~

假设内存满了,OOM,堆内存不够! Java.lang.OutOfMemoryError:java heap space,在JDK8以后,永久存储区改了个名字(元空间)

新生区

1.类:诞生和成长的地方,甚至死亡!

2.伊甸园,所有的对象都是在伊甸园区new出来的!

3.幸存者区(0,1)

真理:经过研究,99%的对象都是临时对象!

养老区


永久区(元空间)

这个区域常驻内存。用来存放JDK自身携带的Class对象。Interfacce元数据,存储的是Java运行时的一些环境或类信息,这个区域不存在垃圾回收!关闭VM虚拟机就回释放这个区域的内存

一个启动类,加载类大量的第三方Jar包。Tomcat部署了太多的应用,大量动态生成的反射类。不断的被加载。知道内存满,就会出现OOM;

jdk1.6之前:永久代,常量用来存放JDK池是在方法区;

jdk1.7 : 永久代,但是慢慢的退化了,‘去永久代’ ,常量池在堆中

jdk1.8之后:无永久代,常量池在元空间

//出现OOM怎么办呢?

1.尝试扩大堆内存看结果,如果还出现问题,肯定是代码出现问题了。

2.分析内存,看一下哪个地方出现了问题,调节JVM内存大小并打印GC的详细信息:-Xms1024m -Xmx1024m -XX:+PrintGCDetails

元空间:逻辑上存在,物理上不存在

一个项目中,突然出现了OOM故障,那么该如何排除~

能够看到代码第几行出错:内存快照分析工具,Eclipse 的MAT,Jprofiler

Dubug,一行行分析代码!

MAT,Jprofiler作用

1.分析Dump内存文件,快速定位内存泄漏;

2.获得堆中的数据

3.获得大的对象

//设置内存调优参数

// -Xms 设置初始化内存分配大小,默认为物理内存的 1/64

// -Xmx 设置最大分配内存,默认为物理内存的 1/4

//-XX:+PrintDCDetails //打印GC垃圾回收信息

// -XX:+HeadDumpOnOutofMemoryError //oom DUMP

//-Xms1m -Xmx8m -XX:HeapDumpOnOutMemoryError

GC:垃圾回收机制

JVM在进行GC时,并不是对这三个区域统一回收,大部分时候,回收都是新生代~

1.新生代 2.幸存区(from,to) 3.老年区

GC两种类:轻GC(普通的GC),重GC(全局GC)

题目:

1.JVM的内存模型和分区~ 详细到每个区放什么?

2.堆里面的分区有哪些? Eden,form,to,老年区,说说他们的特点!

3.GC的算法有哪些? 标记清除法,标记压缩,复制算法,引用计数器,怎么用的?

4.轻GC和重GC分别在什么时候发生?

GC常用算法

1.引用计数器(引用则+1,用完则-1)

2.复制算法(Copying):每次GC都会把EDen活的对象一道幸存区中:一旦Eden区被GC后,就会是空的!

谁空谁是to(from,to)

当一个对象经理了15次GC,都还没有销毁, -XX: -XX:MaxTenuringThreshold=15(默认)

通过这个参数可以设定进入老年代的时间

优点:没有内存的碎片

缺点:浪费了内存空间~ 多了一半空间永远是空to,假设对象100%存活

复制算法最爱使用场景:对象存活度较低的时候:新生区~

3.标记清除算法(Mark and Sweep)

扫描这些对象:对或者对象进行标记

清除:对没有标记的对象,进行清除

优点:不需要额外的空间!

缺点:两次扫描,严重浪费时间,会产生内存碎片。

4.可达性分析算法

通过判断对象的引用链是否可达来决定对象是否可以被回收。

总结

内存效率:复制算法>标记清除算法>标记压缩算法

内存整齐度:复制算法=标记压缩算法>标记清除算法

内存利用率:标记压缩算法=标记清除算法>复制算法

思考一个问题:难道没有最有算法吗?

答案:没有,没有最好的算法,只有最合适的算法----》 GC:最合适就是利用分代收集算法

年轻代:存活率低,复制算法!

老年代:

区域大:存活率

标记清除(内存碎片不是太多)+标记压缩混合实现

文章来源:https://blog.csdn.net/Tony666688888/article/details/135490544
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。