JVM相关知识

一、JDK版本

1. 字符串常量池

     在 JDK 1.7 之前,运行时常量池(包括字符串常量池)存放在方法区。

      在 JDK 1.7 时,字符串常量池被从方法区转移至 Java 堆中,注意并不是运行时常量池,而是字符串常量池被单独转移到堆,运行时常量池剩下的东西还是方法区中。

      在 JDK 1.8 时,此时字符串常量池还在堆中。

二、JVM内存管理机制

Java语言本身不能操作内存,它的一切是交给JVM进行管理和控制的。

当编译器将java源文件编译成.class文件后JVM会开辟出一个空间。会将类加载器加载的信息存放到运行时数据区

该区域分5个部分组成:栈、堆、方法区、程序计数器、本地方法栈。

1、栈

存放着java方法执行的内存模型,是线程私有的,每一个方法都对应一个栈帧(先进后出)。栈帧中存储局部表,操作数栈,动态链接、出口等。

局部变量表:存放八大基本数据类型和对象引用地址

操作数栈:用来操作的,加入有个代码中有 i = 6* 7;他在一开始就会进行操作,然后将操作后的结果存放到局部变量表中。

动态链接:如果该方法中调用了其他方法,就要链接到别的方法中区,这就是动态链接存储链接的地方。

出口:存储方法执行完成后返回的地址

2、堆:

内存中最大的一块区域。是线程共享的,是用来存放对象实例(对象本身和数组)的。、

从jdk1.7开始,字符串常量池在堆中。

3、方法区:

线程共享的,但是是线程安全的,多个线程访问时只能由一个线程使用该数据,其他线程需要等待

存储的内容:类的全路径名,类的访问修饰符,类的类型(类和接口)、虚拟机加载的类信息,静态变量。

public class PersonTest {
    public static void main(String[] args) {
        int a = 18;
        int b = 10;
        long c = add(a,b);
        System.out.println("c = "+c);

        Person2 p = new Person2("小明",18,'男');
        p.showInfor();

    }
    public static long add(int a, int b) {
        int x = a;
        int y = b;
        int z = x + y;
        return z;
    }
}

下图为上述代码的jvm

4.程序计数器

可以看作是线程所执行的字节码的行号指示器,字节码解释器工作时候根据这个计数器的值来执行下一条命令,通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理

在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程切换回来的时候能够知道该线程上次运行到哪了。

他的生命周期随着线程的创建而创建,线程的结束而死亡

5.本地方法栈

本地方法栈则为虚拟机使用到的 Native 方法服务

本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。

方法执行完毕后相应的栈帧也会出栈并释放内存空间,

三、GC

当main方法结束后,栈帧消失,第二条线断掉,此时没有任何引用指向3那个对象,这样的对象会被认为是垃圾垃圾,等待GC来回收。

如果这样的对象多了就会造成内存溢出。

编程时,如果对象用了几次后,不在使用,应该把对象指向null等待GC处理。

四、类加载过程

加载、连接(验证、准备、解析)、初始化

1.类加载

将.class文件的二进制字节流读入内存(1.7之前为JVM内存,1.8之后为本地内存)

本地内存和JVM内存的区别如下:JVM内存是虚拟机在执行时分配的内存区域,受虚拟机内存大小参数控制,超过参数设置的大小会报OOM;本地内存是不受虚拟机内存参数限制的,只受物理内存容量限制,不会发生GC,但如果占用超过物理内存,仍会报OOM12JVM内存只是进程空间的一部分,除此之外还有代码段、数据段、内存映射区、内核空间等,这些被JVM之外的部分称为本地内存

并在堆内存中为之创建Class对象,作为 .class进入内存后数据的访问入口。在这里只是读入二进制字节流,后续的验证就是要拿二进制字节流来验证.class文件,验证通过,才会将.class文件转为运行时数据结构

2.连接

2.1 验证

    保证加载进来的字节流符合JVM的规范,不会堆JVM有安全性问题,其中有元数据的验证,例如检查是否继承了final类,还有符号引用的验证,例如校验符号引用是否可以通过全限定名找到,或者是检查符号引用的权限(private,public)是否符合语法规定等。

(符号引用就是字符串,比如方法的全限定名 com.example.MyClass.myMethod)

2.2 准备

   准备阶段的目的就是为类的类变量开辟空间并赋默认值。

1、静态变量是基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0
2、静态变量是引用类型的,默认值为null
3、静态常量默认值为声明时设定的值

例如:public static final int i = 3; 在准备阶段,i的值即为3

2.3 解析

该阶段的主要职责为将Class在常量池中的符号引用转变为直接引用,此处针对的是静态方法及属性和私有方法与属性,因为这类方法与私有方法不能被重写,静态属性在运行期也没有多态这一说,即在编译器可知,运行期不可变,所以适合在该阶段解析,譬如类方法main替换为直接引用,为静态连接,区别于运行时的动态连接(后续我会写关于JVM内存结构的文章,在讲解栈帧时会介绍动态链接)。
        符号引用即字符串,说白了可以是一个字段名,或者一个方法名;直接引用即偏移量,说白了就是类的元信息位于内存的地址串,例如,一个类的方法为test(),则符号引用即为test,这个方法存在于内存中的地址假设为0x123456,则这个地址则为直接引用。
 

3.初始化

       该阶段主要是为类的类变量初始化值的,初始化有两种方式:
1、在声明类变量时,直接给变量赋值
2、在静态初始化块为类变量赋值

目录

一、JDK版本

1. 字符串常量池

二、JVM内存管理机制

1、栈

2、堆:

3、方法区:

三、GC


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值