美文网首页
深入了解JVM(一)

深入了解JVM(一)

作者: HardMan | 来源:发表于2021-10-03 19:54 被阅读0次

定义:

Java Visual Machine(JVM),Java程序的运行环境,这里指Java二进制字节码的运行环境。
特点
一次编写,跨平台运行。JVM屏蔽了字节码跟底层操作系统的差异,对外提供了一致的运行环境。JVM解释了字节码的流程,实现了跨平台机制。
自动内存管理,垃圾回收功能。
数组下标越界检查。Java程序遇到下标越界会直接抛异常,但是不会去覆盖越界的那块内存的数据。相较于C/C++语言(会覆盖掉那块内存的值),可以说抛异常是更友好的一种处理机制。

JVM,JRE、JDK的区别

image.png

从这个图中可以看出 他们之间是一种逐层向上,互相包含的关系。上一层是下一层的基础上的进一步补充。

JVM结构

JVM结构

1、程序计数器(Program Counter Register)

概念:当Java文件编译成二进制字节码文件后,一行行代码变成了一行行JVM指令,此时的指令还不能直接交给CPU去执行,需要通过解释器翻译成一条条机器码,再交给CPU去执行。程序计算器的作用是在当前指令运行时,记住下一条指令运行的地址。当指令被加载进内存当中时,每条指令的前面都会带有一个地址信息。根据这个地址信息,就能找到是哪条指令去执行它。在物理上,是通过寄存器去实现。寄存器可以说在整个CPU组件里读写速度最快的一个单元。
特点:线程私有。当多线程并发时,CPU的调度器会为每个线程分配一个时间片,比如说,线程1在时间片内代码没有执行完,会先暂停,然后切换到线程2去运行。当从线程2又切回到线程1时,这个时候要知道该从那里继续往下执行,那这也需要用到程序计数器。线程1的计数器记录的是线程1中的下条指令,跟线程2是独立开的。所以说是线程私有的。
不会内存溢出。因为计数器记录的永远是下一条指令的地址,所以不存在内存溢出的情况。

2、JVM 栈(stack)

概念:JVM的每个线程运行时,都需要一块内存空间。虚拟机栈是每个线程运行需要的内存空间。
一个栈内是由多个栈帧(Frame)组成,栈帧是方法时运行所需要的内存,像方法内的变量、参数、返回值都是会占用内存空间,因此事先就得把这些地址空间给预留出来。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        method1();
    }

    public void method1(){
        int a=10;
        method2(a);
    }

    private int method2(int a) {
        int b=20;
        int sum=a+b;
        return sum;
    }
}
具体演示

上述代码我们用debug跟到method2方法内时,我们发现当前栈内存在着oncreate、method1、method2,根据先进后出的原则,最后调用的method2方法位于栈顶(栈内还有其它许多栈帧,是由于Android程序在执行到oncreate方法之时,已经执行了一系列其它方法,这里暂不展开讨论,了解即可)。

特点:
1、不涉及到垃圾回收。栈内的方法,在执行结束后,会被弹出栈,也就是方法结束时,会自动进行内存回收。
栈内内存分配不是越大越大。栈内存分配的大 只是说可以存放的栈帧会更多,递归时可以递归更多次。但栈内存分配多了,必然会导致其它内存分配得少了,会导致线程数量变少,反而会运行更慢。
2、方法内的局部变量是否线程安全?

  • 如果方法内的变量,没有逃离方法的作用范围,那它是线程安全的
  • 如果是局部变量引用的对象,并且逃离了方法的作用范围(比如参数和返回值对象,可能会被其它线程所访问到),需要考虑到线程安全。

栈内存溢出

  • 栈内栈帧过多时,譬如递归没有设置结束时,栈内会存在大量的递归函数,导致溢出。
  • 栈帧过大导致内存溢出。

3、本地方法栈(Native Method Stacks)

java在调用本地的一些方法时,需要给这些本地方法提供内存空间。

4、堆(Heap)

通过new关键字创建的对象,都会使用堆空间。
特点

  • 它是线程共享的,堆中对象需要考虑线程安全的问题。
  • 有垃圾回收机制

堆内存溢出
当堆内存中创建大量对象,且对象存在引用,无法被垃圾回收时,便可能会导致内存溢出。在开发时,需要注意,当某个对象不再使用的时候,要检查是否仍被其它对象持有引用。

5、方法区(Method area)

方法区主要存储被虚拟机加载的类的信息,常量、静态变量。
二进制字节码 class文件的格式
java文件在虚拟机上是以class文件存在的,它是二进制字节码。我们需要通过工具来看懂它。

//将java文件编译成class文件
D:\demo>javac Hello.java
//查看class文件的信息
D:\demo>javap -v Hello.class
public class Test {
    public static void main(String[] args) {
        System.out.println("Hello,world");
    }
}
Classfile /D:/demo/Hello.class
------------------类的基本信息-----------------------------
  Last modified 2021-10-3; size 415 bytes
  MD5 checksum 09b1098c7b153143ee7f674157742226
  Compiled from "Hello.java"
public class Hello
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER

-------------------常量池-----------------------------------------
Constant pool:
   #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V
   #2 = Fieldref           #16.#17        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #18            // Hello,world
   #4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #21            // Hello
   #6 = Class              #22            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               SourceFile
  #14 = Utf8               Hello.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = Class              #23            // java/lang/System
  #17 = NameAndType        #24:#25        // out:Ljava/io/PrintStream;
  #18 = Utf8               Hello,world
  #19 = Class              #26            // java/io/PrintStream
  #20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V
  #21 = Utf8               Hello
  #22 = Utf8               java/lang/Object
  #23 = Utf8               java/lang/System
  #24 = Utf8               out
  #25 = Utf8               Ljava/io/PrintStream;
  #26 = Utf8               java/io/PrintStream
  #27 = Utf8               println
  #28 = Utf8               (Ljava/lang/String;)V
------------------------方法定义---------------------------------

{
//构造方法
  public Hello();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0
//main方法
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V  //参数 返回值
    flags: ACC_PUBLIC, ACC_STATIC //访问修饰符
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello,world
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 3: 0
        line 4: 8
}
SourceFile: "Hello.java"

解释器在解释虚拟机指令的时候,根据#后的数字,在常量池进行查表,比如#2对应常量池里的 #2 = Fieldref #16.#17 ; #2再从#16,#17中去找,直到最后找到需要执行的类名、方法名、参数信息,字节量等信息。
常量池本质上就是一张表,通过前面的地址,找到这些信息。

运行常量池:常量池是class文件中的,当class被加载的时候,它的常量池信息会被放入运行常量池信息中,#前面的地址也会变成真实地址信息。

相关文章

  • 深入了解JVM(一)

    定义: Java Visual Machine(JVM),Java程序的运行环境,这里指Java二进制字节码的运行...

  • 深入JVM内核 目录

    深入JVM内核 目录 深入JVM内核1 初识JVM深入JVM内核2 JVM运行机制深入JVM内核3 常用JVM配置...

  • 深入了解JVM

    深入了解JVM JVM的实现需要遵守,这是官方提供的规范Java SE Specificat...

  • 初见JVM内存区域

    初见JVM内存区域 JVM一个重要的机制就是自动内存管理机制,为了深入理解JVM的内存管理机制,了解JVM的内存...

  • Java学习路径

    1.深入了解JVM/JRE/JDK "JVM是Java程序唯一认识的操作系统,其可执行文件为.class" JVM...

  • 一篇笔记整理JVM工作原理

    前言: 想提高Java开发,了解jvm是必不可少的。它让开发者了解他们的代码,jvm是如何变异与运行。深入了解jv...

  • 一篇笔记整理JVM工作原理

    前言: 想提高Java开发,了解jvm是必不可少的。它让开发者了解他们的代码,jvm是如何变异与运行。深入了解jv...

  • JVM(二)内存与垃圾回收|类加载子系统

    在JVM概述中我们已经了解了JVM体系结构,下文将深入介绍JVM体系结构之一的类加载子系统。 目录 1 类加载子系...

  • JVM浅入浅出

    说是浅入浅出,其实还是需要在入和出的过程中,进行一个深入的了解。在了解JVM之前,我其实是从比较常见的JVM面...

  • Java基础-深入理解Javaclass文件格式

    对于理解JVM和深入理解Java语言,学习并了解class文件的格式都是必须要掌握的功课。原因很简单,JVM不会理...

网友评论

      本文标题:深入了解JVM(一)

      本文链接:https://www.haomeiwen.com/subject/spomnltx.html