Java 运行原理


1. Java的运行机制

1.1 运行过程

  1. 编写 Java代码,产生后缀名为.java的文件

  2. 编译 java文件,产生后缀名为.class的文件

  3. 在虚拟机中运行class文件,看到程序运行的结果

1.2 虚拟机(JVM)

  • java是在虚拟机中运行的

  • 优势: 程序可以在任意操作系统中运行 -> 跨平台

  • 一套代码可以在多个平台运行 -> 减少开发成本


2. 内存

2.1 什么是内存

也叫做随机访问存储(Random Access Memory,简称RAM)是计算机中的一种主要存储设备。它可以快速读取和写入数据。

作用: 软件运行时临时存储数据

2.2 内存地址

即对内存单元的编号

作用: 快速查询

2.2.1 内存命名规则

n位操作系统 -> 用n位的二进制表示

但是太长了,不方便阅读,所以会转成十六进制表示

举例:

计算机实际的内存地址:

00000000 00000000 00000000 00000000 01101100 11011110 01010101 00100010

转成十六进制:

0x``6CDE5522


3. java中的内存分配

学习意义: 深入理解数组与面向对象的知识

Java为了更好的管理内存,把内存分为了五个模块:

栈内存:

每个线程都有自己独立的栈,目前只要考虑一个即可,方法被调用进栈执行,执行完毕出栈

简单理解:栈跟方法有关

堆内存:

所有线程共享,存储对象、数组、字符串常量池

简单理解:堆跟new关键字有关,只要通过new关键字开辟的小空间都是开在堆内存中的

方法区:

JDK7永久代实现,JDK8+元空间实现,从虚拟机内部移到本地内存。存储字节码信息、常量、静态变量

简单理解:方法区是存储class字节码文件的, 当运行一个类的时候,会把这个类的字节码文件加载到内存中临时存储

本地方法栈:

调用本地Native方法

程序计数器:

每个线程独立、记录当前线程执行的字节码指令地址(行号)

Java 复制代码
public class Memory {
    public static void main(String[] args) {
       int a = 10;
        int b = 20;
        sout("交换前:" + a + ", " + b);
        change(a, b);
        sout("交换后:" + a + ", " + b);
    }

    public static void change(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }
}

完整流程如下:

  1. 把相关类的字节码文件,加载到方法区。此时Memory.class就在内存中了

  2. 虚拟机自动调用main方法,main方法,被加载进栈,准备从上往下依次执行代码。

  3. 定义变量a,定义变量b,在main方法当中,就有了两个小空间,分别叫做a和b,存储数据10和20

  4. 调用change方法,方法被调用,进栈执行。chang里面有两个形参a和b,记录的是传递过来的10和20。

内存图解如下:

!NOTE

基本数据类型,变量里面记录的是真实的数据,传递也是真实的数据。两个变量ab,变量a把真实的数据给b了,b想怎么改,就怎么改,不会影响到a里面记录的值。


4. 数组的内存分配

Java 复制代码
public class Memory {
    public static void main(String[] args) {
       int[] arr = {1, 2, 3};
    }
}

完整流程如下:

  1. 把相关类的字节码文件,加载到方法区。此时Memory.class就在内存中了

  2. 虚拟机自动调用main方法,main方法,被加载进栈,准备从上往下依次执行代码

  3. 创建数组的这行代码,左右两部分在不同的内存中

  4. 等号的左边:arr其实就是一个变量,是在栈里面的。数据类型int[],表示能存int类型数组的地址值

  5. 等号的右边:完整的格式中有new,所以是在堆里面开辟一个小空间

  6. 又因为,数组的长度是3,所以,又把new出来的空间,划分了3个小格子,每一个格子都有自己的索引,并存储数据:1,2,3

  7. 通过中间的等号(赋值运算符),把右边数组的地址值,赋值给左边的变量arr,这样通过arr记录的内存地址就可以找到右边的数组了

以上这就是数组在内存中完整的结构。内存图解如下:

!NOTE

  1. 基本数据类型(int)
    存值
  2. 引用数据类型(eg:数组)
    存地址

5.数组在方法中进行传递

数组在方法当中进行传递跟变量在方法当中进行传递是完整不一样的

代码如下:

Java 复制代码
public class Memory {
    public static void main(String[] args) {
       int[] arr = {1, 2, 3};
        System.out.println("交换前:"arr[0]+arr[1]+arr[2]);
        change(arr);
        System.out.println("交换后:"+arr[0]+arr[1]+arr[2]);
 }
    public static void change(int[] arr) {
        int temp = arr[0];
        arr[0] = arr[2];
        arr[2] = temp;
    }

完整流程如下:

  1. 把相关类的字节码文件,加载到方法区。此时Memory.class就在内存中了

  2. 虚拟机自动调用main方法,main方法,被加载进栈,准备从上往下依次执行代码

  3. 创建数组等号的左边:在栈里面定义一个叫做arr的变量,用于存储数组的地址值

  4. 等号的右边:堆里面开辟一个小空间,存储数组的数据

  5. 把右边数组的地址值,赋值给左边的变量arr

内存图解如下:

  1. 通过arr依次获取0索引,1索引,2索引。打印数据:1,2,3

  2. 调用了change方法,方法被调用,进栈执行。change方法里面有一个形参,也叫做arr,也记录地址0x0011, 通过0x0011地址值,也能找到右边的数组

备注: 在调用方法的时候,实际参数如果是变量,变量记录什么就传递什么。

内存图解如下:

  1. 执行change里面的代码,交换首尾元素

内存图解如下:

  1. 交换完毕,change方法所有代码执行完毕,从栈里面出去。方法出栈了,方法里面的变量,也从内存中消失了

  2. 继续执行main方法下面的代码,通过arr,再去访问元素就是修改之后的结果了

    最终打印:3,2,1


6. 总结

  1. java虚拟机把内存分成了栈/堆/方法区/本地方法栈/程序计数器5个部分
  2. : 方法, : new关键字, 方法区: 字节码文件
  3. 基本数据类型在内存中记录真实数据 , 传递的也是真实的数据
  4. 引用数据类型在内存中记录地址值 , 传递地址值

相关推荐
難釋懷2 小时前
安装Canal
java
是苏浙3 小时前
JDK17新增特性
java·开发语言
阿里加多6 小时前
第 4 章:Go 线程模型——GMP 深度解析
java·开发语言·后端·golang
likerhood6 小时前
java中`==`和`.equals()`区别
java·开发语言·python
小小李程序员6 小时前
Langchain4j工具调用获取不到ThreadLocal
java·后端·ai
zs宝来了7 小时前
AQS详解
java·开发语言·jvm
telllong7 小时前
Python异步编程从入门到不懵:asyncio实战踩坑7连发
开发语言·python
wjs20249 小时前
JavaScript 条件语句
开发语言