【JVM】内存模型全面解读

根据JVM规范,JVM 内存共分为虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。为了方便培养大家的全局观,本文从java文件编译开始介绍

本文基于jdk1.8,其他版本的介绍文中会有标明

Java内存模型

在这里插入图片描述

  • 线程私有:虚拟机栈,本地方法栈,程序计数器
  • 线程共享:堆,方法区,直接内存

1. java文件编译成Class文件

在这里插入图片描述

编译过程
从javac的代码的总体结构来看,编译过程大致分为1个准备过程和3个处理过程

  1. 准备过程:初始化插入式注解处理器
  2. 解析和填充符号表过程,包括:词法语法分析,将源代码的字符流转变成标记集合,构造出抽象语法树,填充符号表。产生符号地址和符号信息
  3. 插入式注解处理器的注解处理过程
  4. 分析与字节码生成过程
    a:标注检查。对语法的静态信息进行检查
    b:数据流及控制流分析,对程序动态运行过程进行检查
    c:解语法糖。将简化代码编写的语法糖还原为原有的格式
    d:字节码生成。将前面代码编写的语法糖还原为原有的格式

编译做了什么

1.常量

2.静态变量

3.静态常量

1.1 jvm有多少中常量池

一提到常量池就头疼,到底有多少常量池呢?位置在哪?都有什么作用?目前查资料了解到的有:Class文件常量池、运行时常量池,全局字符串常量池,以及基本类型包装类对象常量池

Class文件常量池
class文件中有一项是constant_pool(常量池),里面主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。
字面量如:文本字符串、final常量值,

举个例子:string a="abc"中,"abc"就是字面量

符号引用包含下面三类:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

运行时常量池
是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,Java语言并不要求常量一定只有编译期才能产生,运行时也可以增加常量。

全局字符串常量池
从jdk7开始,方法区中的字符串常量池移到了Java堆中,这也意味着字符串常量池是所有线程共享的,JVM做的一个优化就是字符串常量池的常量是唯一的。

举个例子:下面这个代码创建了几个对象

String a=new String ("abc") 

回答:可能是一个,也可能是两个,因为String的构造函数,JVM会先去字符串常量池去找"abc",如果有就不再创建,根据new命令会去堆中创建一个String对象,所以是一个;如果字符串常量池中没有,就会在常量池中创建一个,堆中创建一个,一共创建了2个。

再深入分析一下,(==如果只基本类型比较就是比较值,如果是对象就是比较地址)
在这里插入图片描述

上图中,s1==s2值为false,印证了 s1指向的是堆中的String对象,s2指向的是字符串常量池中的String对象,s3也是指向字符串常量池中的String对象。

基本类型包装类对象常量池

2. 类加载子系统加载.Class文件(类加载机制)

类加载机制:https://blog.csdn.net/yujing1314/article/details/105935391
双亲委派机制:https://blog.csdn.net/yujing1314/article/details/105838620

3. 运行时数据区

3.1 堆

堆的内存分配
在这里插入图片描述
简述
堆分为新生代和老年代,比例为1:2,新生代又分为伊甸园区,幸存者0区和幸存者1区

主要存储
JVM百分之95的对象都存在于堆中,所以垃圾回收算法主要针对的也是堆区

垃圾回收器
新生代的垃圾回收算法有Serial、Parnew等
老年代的垃圾回收器有CMS、PS等

垃圾回收算法
新生代的垃圾回收算法:标记-复制
老年代的垃圾回收算法:标记清除、标记整理

3.2 方法区

在这里插入图片描述

方法区是一种规范,1.7之前的实现是永久带,因为永久带容易导致内存溢出,1.7以后就去掉了永久带,将方法区的实现移到了元空间之中

3.3 虚拟机栈

在这里插入图片描述
栈是由栈帧组成的,一个栈帧中存了局部变量表、操作数栈、动态链接、方法返回地址

3.4 程序计数器

程序计数器中储存了下一条指令的地址

3.5 本地方法栈

本地方法栈主要是针对本地方法的

猜你喜欢

转载自blog.csdn.net/yujing1314/article/details/107531157