深入浅出学Java(一)-Java内存机制

111 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情

一、JVM的内存结构

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机的进程启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁.

image.png

二、Java的内存模型

Java内存模型中线程间共享变量有:实例域、静态域、数组元素,存储在堆内存中.--线程间共享

线程间私有:局部变量(local variables),方法定义参数(format method parameters),异常处理参数(exception handler parameters)

2.1 堆

Java的堆是一个运行时数据区,类的(对象从中分配空间.这些对象通过new,newarray,anewarray和multianewarray等指令建立,它们不需要程序代码来显式地释放.

堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据.

但缺点是,由于要在运行时动态分配内存,存取速度较慢.

2.2 栈

栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。

但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性.

栈中主要存放一些基本类型的变量数据(int,short,long,byte,float,double,boolean,char)和对象句柄(引用)

2.3 方法区

又叫静态区,跟堆一样,被所有的线程共享.方法区包含所有的class和static变量

方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量

2.4 字符串常量池

JDK 1.7 及之后版本的JVM已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。

JDK1.8开始,取消了Java方法区,取而代之的是位于直接内存的元空间(metaSpace)。

方法区-->堆内存

2.5 本地方法栈(Native Method Stack):

与操作系统相关,用于管理本地方法的调用,线程私有,允许被实现成固定或者是可动态扩展的内存大小。

2.6 寄存器(pc Register):

与CPU相关,共有四个寄存器

程序记数寄存器:跟踪程序执行的准确位置

堆栈指针寄存器:指示操作栈项

框架寄存器:指向当前执行的环境

变量寄存器:指向当前执行环境中第一个本地变量

image.png

三、为什么JVM的方法栈中要有程序计数器

程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的信号指示器。

字节码解释器工作通过改变这个计数器的值来选取下一条需要执行的字节码指令,分子、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成

另外,为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,个线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”内存

主要有两个作用

  • 1.字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。

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

注意:程序计数器是为一个一个不会出现OutOfMemoryError的内存区域,他的生命周期随着线程的创建而创建,随着现成的结束而死亡。