JVM内存结构与内存区域

JVM的内存结构包括五大区域:程序计数器,虚拟机栈,本地方法栈,堆区,方法区

虚拟机栈:一个线程独有的,每次启动一个线程,就创建一个jvm虚拟机栈,线程退出就销毁,这里主要保存线程的本地变量名和局部变量值。所以Java栈也是"线程私有"的内存区域。这个栈中又会对应包含多个栈帧。每调用一个方法时就会往栈中创建并压入一个栈帧,栈帧是用来存储方法数据和部分过程结果的数据结构,每一个方法从调用到最终返回结果的过程,就对应一个栈帧从入栈到出栈的过程。

本地方法栈:本地方法栈(Native Method Stack)和虚拟机栈的作用相似,不过虚拟机栈是为Java方法服务的,而本地方法栈是为Native方法服务的。调用本地jni方法的时候创建。这里分配的jvm之外的内存空间。方法调用结束之后销毁。

堆区:堆(heap)是存储java实例或者对象的地方,是GC的主要区域,同样是线程共享的内存区域。

方法区:存储类结构信息的地方,包括常量池、静态变量、构造函数等类型信息,类型信息是由类加载器在类加载时从类文件中提取出来的。方法区是线程共享的 。常量池是方法区的一部分,主要保存class结构中的常量值,例如String值,public static final 类型的值

程序计数器:保存着当前线程执行的虚拟机字节码指令的内存地址。Java多线程的实现,其实是通过线程间的轮流切换并分配处理器执行时间的方式来实现的。每个线程都会设立一个程序计数器,并且各个线程之间不会互相影响,程序计数器为"线程私有"的内存区域。

例1:

例2:

上面main方法中运行的程序过程如下:

  (1)用户创建了一个Student对象,运行时JVM首先会去方法区寻找该对象的类型信息,没有则使用类加载器classloader将Student.class字节码文件加载至内存中的方法区,并将Student类的类型信息存放至方法区。

  (2)接着JVM在堆中为新的Student实例分配内存空间,这个实例持有着指向方法区的Student类型信息的引用,引用指的是类型信息在方法区中的内存地址。

  (3)在此运行的JVM进程中,会首先起一个线程跑该用户程序,而创建线程的同时也创建了一个虚拟机栈,虚拟机栈用来跟踪线程运行中的一系列方法调用的过程,每调用一个方法就会创建并往栈中压入一个栈帧,栈帧用来存储方法的参数,局部变量和运算过程的临时数据。上面程序中的stu是对Student的引用,就存放于栈中,并持有指向堆中Student实例的内存地址。

  (4)JVM根据stu引用持有的堆中对象的内存地址,定位到堆中的Student实例,由于堆中实例持有指向方法区的Student类型信息的引用,从而获得add()方法的字节码信息,接着执行add()方法包含的指令。

总结

   1、所有线程共享的内存数据区:方法区,堆。线程私有的区域:虚拟机栈,本地方法栈程序计数器

   2、存放于栈中的东西如下:
      2.1 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)。对象都存放在堆区中。

    2.2 每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。
      2.3 方法的形式参数,方法调用完后从栈空间回收
      2.4 引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC

   3、存放于堆中的东西如下:

    3.1 存储的全部是对象,每个对象包含一个与之对应的class信息

    3.2 JVM只有一个堆区(heap)被所有线程共享,堆区中不存放基本类型和对象引用,只存放对象本身

   4、存放于方法区中的东西如下:

    4.1 存放线程所执行的字节码指令

    4.2 跟堆一样.被所有线程共享.方法区包含:所有的class和static变量

    4.3 常量池位于方法区中

 

猜你喜欢

转载自blog.csdn.net/ChaunceyChen/article/details/86565676
今日推荐