JVM数据区解析

这篇文章以java为例讲解java源码到字节码到字节码对象再到jvm的内存中整个过程为例。从而来理解JVM的原理。JVM由ClassLoader,JVM运行时数据区,执行引擎三部分构成。这篇文章主要会讲解JVM运行时数据区的各个分区的内在特点以及各个分区之间的关系。

一,JVM简介

JVM(Java Virtual Machine)也就是java虚拟机。用来运行字节码码的。可以运行Java,kotlin,Scala,Clojure,Groovy,Jython,JRuby,Ceylon,Eta,Haxe 10余种语言编译的字节码。

后面就以Java来讲解。先给上一张图。可以看出JVM是在这个JDK中最底层的一小部分。但是他却起到到来了极其重要的作用。

java源码通过javac编译成.class的字节码文件然后在由java虚拟机运行。java具有垮平台的特点。它跨平台就是通过不同的操作系统上装上不同的JDK从而拥有不同的JVM来实现的跨平台。也就是一份编译出来的字节码文件可以在不同的操作系统的JVM上运行。

JVM由ClassLoader,JVM运行时数据区,执行引擎三部分构成。

下面是官方图:

下面来一个中文的简图,文章主要讲解运行时数据区的内存空间的分区,每个分区的内在特点,以及分区间的相互关系。

 

 

 

二,方法区

说到方法区就要提到 元空间,永久带 。方法区是规范,元空间,永久带是具体实现。

  • 永久带是jdk8之前方法区的具体实现。他是放在堆里面的,所有他也会出现oom(out of memory),也会触发GC。
  • 元空间是jdk8以后方法区的具体实现。他是放在直接内存中的。也就是操作系统内存。所有会出现native memory

   1,元空间的默认大小是20.75M。最大内存就是系统内存。(目前系统64位,其中16位为保留位,最大内存就为2的48次方=256T)

   2,元空间调优

         (1)元空间最大最小设置成一样。这样可以防止内存抖动。

         (2)元空间设置为多物理内存的1/32。具体多少需要进行调试。

         (3)设置元空间的时候比起实际使用大小预留20%到30%这样比较安全。

 方法区里面存放了:常量,静态变量,类信息。              

三,程序计数器

 程序计数器是指向当前线程执行的字节码指令的(地址)行号。

 在cmd窗口执行命令   javap  -c  Test.class >Test.txt

打开Test.txt文件。程序计数器就是存放这个行号的。

Compiled from "Test.java"
public class AAA.Test {
  public AAA.Test();
    Code:
       0: aload_0
       1: invokespecial #12                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: new           #3                  // class java/lang/Object
       8: dup
       9: invokespecial #12                 // Method java/lang/Object."<init>":()V
      12: putfield      #14                 // Field object:Ljava/lang/Object;
      15: return

  public int add();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        100
       9: imul
      10: istore_3
      11: iload_3
      12: ireturn

  public static void main(java.lang.String[]);
    Code:
       0: new           #1                  // class AAA/Test
       3: dup
       4: invokespecial #28                 // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #29                 // Method add:()I
      12: istore_2
      13: getstatic     #31                 // Field java/lang/System.out:Ljava/io/PrintStream;
      16: iload_2
      17: invokevirtual #37                 // Method java/io/PrintStream.println:(I)V
      20: return
}

 

四,虚拟机栈(线程栈)

虚拟机栈里面存放的是栈帧,一个方法对应一个栈帧。

栈帧中存放了:局部变量表,操作数栈,动态链接,方法出口。

  • 局部变量表:就是这个方法类的局部变量汇总。
  • 操作数栈:这些局部变量在赋值给变量引用之前要先压入操作数栈。以及进行计算的时候临时存放变量的栈。
  • 动态链接:就是存放这个方法在方法区内的内存地址。
  • 方法出口:就是返回现场。比如在执行到main方法的第9行指令开始调用add()方法,这个时候就会把这个行号存到方法出口中,当add()方法执行结束然后就回到main()方法中执行第10行指令。

一个方法执行完JVM需要做的事情。

  • 1,恢复局部变量表指针
  • 2,恢复操作数栈指针
  • 3,恢复程序技术器。
  • 4,如果方法有返回地址,需要返回。
  • 5,清理栈帧。(程序计数器去完成的)

这个是上面图对应的java代码

public class Test {
	public int add() {
		int a = 1;//局部变量
		int b = 2;//局部变量
		int c = (a+b)*100;
		return c;
	}
	
	public static void main(String[] args) {
		Test text=new Test();
		int result = text.add();
		System.out.println(result);
	}
}

 

五,堆

1,堆是用来存放对象的地方

2,堆的默认大小

  •       最小是是物理内存的1/64
  •       最大是1/4

3,堆内存分区

  •      yang(年轻代)和old(老年代)两部分。默认比例为1:2
  •      yang(年轻代)又分为Eden(伊甸园区)和survivor0区,survivor1区。默认比例为8:1:1

 

六,本地方法栈

   本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

 

七,个内存区之间的关系

   虚拟机栈-->方法区   动态链接。(虚拟机栈中的栈帧对应的方法在方法区的内存地址)

   堆-->方法区   关联是class Pointer(也就是对象执行所对应的类的Class对象所属地址)

   方法区-->堆   类里面的静态对象引用。(例如类里面的public static Test test = new Test();)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值