面试整理-JVM内存模型及类加载

目录

一、JVM内存模型

1. 堆

2. 方法区

3. 虚拟机栈

4. 本地方法栈

5. 程序计数器

二、类的加载过程   

1. 类的加载机制

2. 类的加载过程

3. 类成员的加载顺序


一、JVM内存模型

当前三大JAVA虚拟机:

1. HotSpot(Sun/Oracle)、2.JRockit(Oracle)、3. J9(IBM,)    

它们都有方法区,但只有HotSpot有永久代(老年代),且JDK1.8及之后改为元空间

五大内存区域:

1. 线程共有:堆,方法区

2. 栈,程序计数器,本地方法栈


1. 堆

线程共享,在虚拟机启动时创建,主要用于存放对象和数组。分为新生代和老年代,比例为1:2。

新生代代可划分为Eden区、survivor1区、survivor2区,默认比例为8:1:1

-Xms:值,初始堆内存大小

-Xmx:值,最大堆内存大小

-Xmn:值,新生代内存大小

2. 方法区

线程共享,在虚拟机启动时创建。JDK1.8之前是堆的一个逻辑分区,称之为“非堆”。该区域主要存放类的元数据信息、运行时常量池、静态变量、即时编译器编译的代码缓存

即时编译:是执行计算机代码的一种方法,在程序执行过程中的执行期而不是执行之前的编译器,通常包括源代码或字节码到机器码的转换

在不同的JDK版本中,方法区中存储的位置及实现是不一样的。

JDK1.8之前:方法区——>永久代

JDK1.8及之后:方法区——>元空间

永久代和方法区是HotSpot虚拟机对虚拟机规范中方法区的两种不同实现方法

区别:永久代是在虚拟机内存中,元空间是在本地内存(不受虚拟机内存大小限制)

为什么要用元空间代替永久代?

1. Oracle为了融合HotSpot JVM和JRockit JVM(新技术)而做出的改变,因为JRockit没有永久代

2. 有了元空间基本上不会出现OOM内存溢出问题

永久代内存大小参数配置:

-XX:PermSize=N,永久代的初始内存大小

-XX:MaxPermSize=N,永久代的最大值,超出抛OOM异常

元空间内存大小参数配置:

XX:MatespaceSize=N,元空间初始值

-XX:MaxMatespaceSize=N,元空间最大值

3. 虚拟机栈

线程私有,java方法执行的内存模型,每个方法执行都会创建一个栈帧,用于存放局部变量表、操作树栈、动态链接、方法返回地址信息等。

局部变量表:一组局部变量值存储空间,用于存放方法参数和方法内部定义的局部变量

操作数栈:一个用于计算的数组,通过入栈和出栈完成一次数据访问(如:先将局部变量表第0和1个索引压入栈,再一次弹出栈并相加,再压入操作数栈中)

Person(方法区) person(虚拟机栈) = new Person()(堆)

4. 本地方法栈

线程私有,和栈内存类似,用来管理JVM调用Native方法时的内存空间

5. 程序计数器

线程私有,记录当前线程要执行字节码的行号指示器,随着线程的创建和销毁而生灭。     

二、类的加载过程   

1. 类的加载机制

a. 加载器的分类

1). 启动类加载器(Boostrap ClassLoad):主要负责加载JAVA_HOME/lib目录中的部分类,比如rt.jar、所有java.*开头的类

2). 扩展类加载器(Extension ClassLoad):主要负责加载JAVA_HOME/lib/ext目录中的一些扩展类,比如javax.*开头的类

3). 应用程序类加载器(Application ClassLoad):主要负责加载用户类路径classPath指定的类

b. 双亲委派机制

如果类加载器要加载一个类,首先会把这个类加载请求委派给父类加载器去完成,如果父类还有父类,则接着向上层父类委托,一直递归到当父类加载器无法完成整个加载请求时,子类才会尝试去加载该类

双亲委派机制的优点

1). 止加载同一个.class文件,避免重复加载,确保一个类的全局唯一性

2). 保护程序安全,防止核心API被篡改

2. 类的加载过程

主要分为三个过程:加载,链接(验证、准备、解析),初始化

1). 加载:将字节码文件加载到jvm内存中,jvm通过双亲委派机制保护jvm内部安全,防止重复加载

2). 链接(分为三个阶段)

a.  验证:验证加载的字节码文件语法或语义是否符合jvm规范,或者对jvm是否有危害动作等

b.  准备:对静态变量赋默认值

c.  解析:把对象的符号引用通过静态和动态解析(多态)为直接引用

3). 初始化:为静态常量和成员变量赋初始值,执行静态代码块

准备阶段和初始化阶段的赋值区别:

3. 类成员的加载顺序

类加载时,类成员的初始化顺序:

a). 初始化父类中静态成员变量、静态代码块

b). 初始化子类中静态成员变量、静态代码块

c). 初始化父类中普通成员变量、非静态代码块、父类构造器

d). 初始化子类中普通成员变量、非静态代码块、父类构造器

静态变量和静态代码块实在类加载的时候进行的,只加载一次。静态方法只在调用的时候被加载

参考资源:

【JVM】Java类加载机制这块算是玩明白了_哔哩哔哩_bilibili

一文以概之:Java类成员加载顺序_java类成员的加载顺序_苏格拉没有底v的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值