自学内容网 自学内容网

JVM的基本概念

目录

一、JVM的内存划分

二、JVM的类加载过程

三、JVM的垃圾回收机制(GC)

四、分代回收


一、JVM的内存划分

一个运行起来的Java进程,就是一个Java虚拟机,就需要从操作系统中申请一大块内存。申请的内存会划分为不同的区域,每个区域有不同的作用。

1、方法区/元数据区 存储的内容为类对象

2、 存储的内容为代码中new的对象

3、代码执行过程中,方法之间的调用关系

4、程序计数器 存放“地址”,表示下一条指令在内存的哪个地方

其中,栈和程序计数器每个线程都有一个。

一个变量处于哪个区域和变量的形态密切相关

局部变量处于栈上

成员变量处于堆上

静态变量(类属性)处于方法区/元数据区上

局部变量和成员变量的区别

1.在类中的位置不同

成员变量:在类中,方法外

局部变量:在方法定义中或者方法声明上

2.在内存中的位置不同:

成员变量:在堆内存中

局部变量:在栈内存中

3.生命周期不同:

成员变量:随着对象的创建而存在,随着对象的消失而消失

局部变量:随着方法的调用而存在,随着方法的调用完毕而消失

4.初始化值不同

成员变量:有默认的初始化值

局部变量:没有默认的初始化值,必须定义、赋值,然后才能使用。

二、JVM的类加载过程

Java程序想要运行起来,就需要让JVM读取到Java中的文件,并且把里面的内容构造成类对象,保存在内存的方法区中。

基本流程:

1、加载

找到.class文件,打开文件,读取文件内容。往往代码中会给某个类“全限定类名”,方便区分。

例如:java.long.String java.util.ArrayList

JVM就会根据这个类名,在一些指定的目录范围内查找。

2、验证

.class文件是一个二进制的格式(每个字节都是有特定含义的),就需要验证当前读到的这个格式是否符合要求。

3、准备

给类对象分配内存空间,只是分配空间,还没有初始化。

4、解析

针对类对象中的字符串常量进行处理,进行一些初始化操作,这个过程把“符号引用”替换成“直接引用”。

5、初始化

针对类对象进行初始化,把类对象中的各个属性都设置好。

三、JVM的垃圾回收机制(GC)

在Java中,new一个对象,也就是“动态内存申请”,当内存不再使用,JVM会自行判断,如果这个内存后面确实不用了,JVM就会自动的把这个内存给回收。

GC的缺陷:

1、系统开销大,要有特定的线程进行扫描

2、效率问题,扫描线程要有一定的周期,不能及时释放

回收步骤:

1、找到要回收的对象,利用可达性分析

有一组线程,周期性的扫描代码中的所有对象,从特定的对象出发,尽可能的进行访问的遍历,把所有能够访问的对象,都标记成“可达”,反之,经过扫描后,未被标记的对象,就是需要回收的垃圾。

2、释放垃圾

1、标记清除

直接把垃圾进行释放,可能会产生很多的内存碎片。

2、复制算法

通过复制的方式,把有效的对象,归类在一起,再统一进行释放。


把内存分成两份,如果1、3、5是垃圾,就把2、4复制到另一份,然后把前一份整体释放。

优点:可以有效的解决内存碎片化的问题

缺点:1、内存要浪费一半,利用率不高

           2、如果有效对象非常多,拷贝的开销就非常大

3、标记整理

如果1、3、5是垃圾,就将2、4往前搬运,然后整体释放。

既能解决内存碎片化的问题,又能处理算法的利用率,但是搬运的开销很大。

四、分代回收

实际上,JVM采用的思路是基础思路的结合体,分代回收。


在新生代中会包含伊甸区和幸存区

伊甸区:刚new出来的新对象,放到伊甸区。从对象诞生,到第一轮扫描分析,这个时间不长,但是,在这个时间里,大部分对象都会变成无用的对象。

幸存区:

1、伊甸区到幸存区

复制算法,每一轮GC扫描后,都能把有效对象复制到幸存区,伊甸区就可以整体释放了。

2、幸存区到幸存区

GC扫描线程也会扫描幸存区,就会把可达的对象,拷贝到幸存区的另一部分。

会进行多轮扫描,每一轮会拷贝很多对象,也会淘汰一部分对象。

3、幸存区到老年代

当对象经过多轮扫描后,JVM认为这个对象短期无法释放,就会把这个对象拷贝到老年代。

老年代:

进入老年代的对象,虽然也会被GC扫描,但频率会降低很多,可以减少开销。

新生代,主要使用复制算法。

老年代,主要使用标记整理。



原文地址:https://blog.csdn.net/2301_80706853/article/details/142441075

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!