第四章 运行时数据区



前言


一、🚗 双亲委派机制

在这里插入图片描述

1、 问题的引出:是否会被外来程序对系统进行破坏

现在我们自己定义了一个 java.lang.String 的Java类,当我们去 new String 的时候会不会去加载这个自定义的String 呢? 显然是不会的,因为如果随意一个类都能被加载到我们的系统中,如果有人恶意的植入一些代码,我们的系统就崩掉了。

在这里插入图片描述

在这里插入图片描述

public class String {
    //
    static{
        System.out.println("我是自定义的String类的静态代码块");
    }

}
public class StringTest {

    public static void main(String[] args) {
        java.lang.String str = new java.lang.String();
        System.out.println("hello,atguigu.com");

        StringTest test = new StringTest();
        System.out.println(test.getClass().getClassLoader());
    }
}

2、总结

在这里插入图片描述

双亲委派机制,就是先让父类加载器进行类的加载,父类不能进行加载时子类进行加载,比如上面自定义的String 类,要进行类加载,会先从 ApplicationClassloader 依次向上委托,到 BootStrapClassLoader ,这时引导类加载器发现是 java.lang.String 包下的类,自己可以加载,就回去加载 JDK 中的String ,而不会加载我们自定义的 String 类。

后面我们又创建了一个 StringTest 的测试类,并获取到了 classLoader 为 AppClassLoader 。他的加载流程是,先从App 到 bootStrap ,bootStrap 发现不归自己管,又会向下委托给扩展类加载器,然后继续向下委托给 AppClassLoader。

在这里插入图片描述

加载 Java的核心类库 rt.jar 会使用引导类加载器,但是当要加载 rt.jar 里面接口的第三方实现子类JDBC,会反向委托给 线程上下文加载器(默认使用 AppClassLoader)进行加载。

在这里插入图片描述

3、双亲委派的优势

在这里插入图片描述

4、沙箱安全机制

在这里插入图片描述

5、其他

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、🚒 运行时数据区

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

线程

在这里插入图片描述
在这里插入图片描述

三、🛺 PC 寄存器

概述(记录下一条程序指令的地址)

记录下一条程序指令的地址

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

举例说明

在这里插入图片描述

对应的字节码文件

在这里插入图片描述

在这里插入图片描述

package com.atguigu.java;

/**
 * @author shkstart
 * @create 2020 下午 6:46
 */
public class PCRegisterTest {

    public static void main(String[] args) {
        int i = 10;
        int j = 20;
        int k = i + j;

        String s = "abc";
        System.out.println(i);
        System.out.println(k);

    }
}

Classfile /G:/Java/JVM/上篇/代码/JVMDemo/out/production/chapter04/com/atguigu/java/PCRegisterTest.class
  Last modified 2020-1-14; size 675 bytes
  MD5 checksum 53b3ef104479ec9e9b7ce5319e5881d3
  Compiled from "PCRegisterTest.java"
public class com.atguigu.java.PCRegisterTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#26         // java/lang/Object."<init>":()V
   #2 = String             #27            // abc
   #3 = Fieldref           #28.#29        // java/lang/System.out:Ljava/io/PrintStream;
   #4 = Methodref          #30.#31        // java/io/PrintStream.println:(I)V
   #5 = Class              #32            // com/atguigu/java/PCRegisterTest
   #6 = Class              #33            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/atguigu/java/PCRegisterTest;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               i
  #19 = Utf8               I
  #20 = Utf8               j
  #21 = Utf8               k
  #22 = Utf8               s
  #23 = Utf8               Ljava/lang/String;
  #24 = Utf8               SourceFile
  #25 = Utf8               PCRegisterTest.java
  #26 = NameAndType        #7:#8          // "<init>":()V
  #27 = Utf8               abc
  #28 = Class              #34            // java/lang/System
  #29 = NameAndType        #35:#36        // out:Ljava/io/PrintStream;
  #30 = Class              #37            // java/io/PrintStream
  #31 = NameAndType        #38:#39        // println:(I)V
  #32 = Utf8               com/atguigu/java/PCRegisterTest
  #33 = Utf8               java/lang/Object
  #34 = Utf8               java/lang/System
  #35 = Utf8               out
  #36 = Utf8               Ljava/io/PrintStream;
  #37 = Utf8               java/io/PrintStream
  #38 = Utf8               println
  #39 = Utf8               (I)V
{
  public com.atguigu.java.PCRegisterTest();
    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 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/atguigu/java/PCRegisterTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=5, args_size=1
         0: bipush        10
         2: istore_1
         3: bipush        20
         5: istore_2
         6: iload_1
         7: iload_2
         8: iadd
         9: istore_3
        10: ldc           #2                  // String abc
        12: astore        4
        14: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        17: iload_1
        18: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
        21: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
        24: iload_3
        25: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
        28: return
      LineNumberTable:
        line 10: 0
        line 11: 3
        line 12: 6
        line 14: 10
        line 15: 14
        line 16: 21
        line 18: 28
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      29     0  args   [Ljava/lang/String;
            3      26     1     i   I
            6      23     2     j   I
           10      19     3     k   I
           14      15     4     s   Ljava/lang/String;
}
SourceFile: "PCRegisterTest.java"

两个常见的问题

在这里插入图片描述
在这里插入图片描述

CPU的时间片

在这里插入图片描述

四、🚈 Java虚拟机栈

1、虚拟机栈的基本内容

虚拟机栈出现的背景

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

虚拟机栈的基本内容

在这里插入图片描述

栈 存在OOM 内存溢出,但是不存在GC 垃圾回收,因为只有进栈和出栈的操作,所以不存在垃圾回收

在这里插入图片描述

虚拟机栈可能出现的异常

在这里插入图片描述

Exception in thread “main” java.lang.StackOverflowError

package com.atguigu.java;

/**
 * 演示栈中的异常:StackOverflowError
 * @author shkstart
 * @create 2020 下午 9:08
 *
 *  默认情况下:count : 11420
 *  设置栈的大小: -Xss256k : count : 2465
 */
public class StackErrorTest {
    private static int count = 1;
    public static void main(String[] args) {
        System.out.println(count);
        count++;
        main(args);
    }

}

在这里插入图片描述

设置栈的大小 -Xss

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2、栈的存储单位

栈中存储什么

在这里插入图片描述

栈的运行原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

栈帧的组成结构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3、局部变量表(当前方法有效)

在这里插入图片描述
在这里插入图片描述

字节码中方法内部的剖析

这里主要看main 方法

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

,

关于Slot 的理解(变量槽)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

变量槽的重复利用

在这里插入图片描述
在这里插入图片描述

4、静态变量与局部变量的对比

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5、操作数栈 (局部变量表和操作数栈都是数组实现)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码追踪

在这里插入图片描述

bipush 是将byte转换为 int 类型
istore 是存入局部变量表的位置索引,从 1就开始是因为 0是一个 this
iload 是取出局部变量表的数据
iadd 是做求和操作

6、栈顶缓存技术(了解即可)

在这里插入图片描述

7、动态连接

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8、方法的调用

在这里插入图片描述
在这里插入图片描述


package com.atguigu.java2;

/**
 * 说明早期绑定和晚期绑定的例子
 * @author shkstart
 * @create 2020 上午 11:59
 */
class Animal{

    public void eat(){
        System.out.println("动物进食");
    }
}
interface Huntable{
    void hunt();
}
class Dog extends Animal implements Huntable{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    @Override
    public void hunt() {
        System.out.println("捕食耗子,多管闲事");
    }
}

class Cat extends Animal implements Huntable{

    public Cat(){
        super();//表现为:早期绑定
    }

    public Cat(String name){
        this();//表现为:早期绑定
    }

    @Override
    public void eat() {
        super.eat();//表现为:早期绑定
        System.out.println("猫吃鱼");
    }

    @Override
    public void hunt() {
        System.out.println("捕食耗子,天经地义");
    }
}
public class AnimalTest {
    public void showAnimal(Animal animal){
        animal.eat();//表现为:晚期绑定
    }
    public void showHunt(Huntable h){
        h.hunt();//表现为:晚期绑定
    }
}

在这里插入图片描述

虚函数就是 父类型引用指向子类型对象方法。

9、虚方法与非虚方法

在这里插入图片描述
在这里插入图片描述

package com.atguigu.java2;

/**
 * 解析调用中非虚方法、虚方法的测试
 *
 * invokestatic指令和invokespecial指令调用的方法称为非虚方法
 * @author shkstart
 * @create 2020 下午 12:07
 */
class Father {
    public Father() {
        System.out.println("father的构造器");
    }

    public static void showStatic(String str) {
        System.out.println("father " + str);
    }

    public final void showFinal() {
        System.out.println("father show final");
    }

    public void showCommon() {
        System.out.println("father 普通方法");
    }
}

public class Son extends Father {
    public Son() {
        //invokespecial
        super();
    }
    public Son(int age) {
        //invokespecial
        this();
    }
    //不是重写的父类的静态方法,因为静态方法不能被重写!
    public static void showStatic(String str) {
        System.out.println("son " + str);
    }
    private void showPrivate(String str) {
        System.out.println("son private" + str);
    }

    public void show() {
        //invokestatic
        showStatic("atguigu.com");
        //invokestatic
        super.showStatic("good!");
        //invokespecial
        showPrivate("hello!");
        //invokespecial
        super.showCommon();

        //invokevirtual
        showFinal();//因为此方法声明有final,不能被子类重写,所以也认为此方法是非虚方法。
        //虚方法如下:
        //invokevirtual
        showCommon();
        info();

        MethodInterface in = null;
        //invokeinterface
        in.methodA();
    }

    public void info(){

    }

    public void display(Father f){
        f.showCommon();
    }

    public static void main(String[] args) {
        Son so = new Son();
        so.show();
    }
}

interface MethodInterface{
    void methodA();
}


在这里插入图片描述
在这里插入图片描述

方法重写的本质

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.atguigu.java3;

/**
 * 虚方法表的举例
 *
 * @author shkstart
 * @create 2020 下午 1:11
 */
interface Friendly {
    void sayHello();
    void sayGoodbye();
}
class Dog {
    public void sayHello() {
    }
    public String toString() {
        return "Dog";
    }
}
class Cat implements Friendly {
    public void eat() {
    }
    public void sayHello() {
    }
    public void sayGoodbye() {
    }
    protected void finalize() {
    }
    public String toString(){
        return "Cat";
    }
}

class CockerSpaniel extends Dog implements Friendly {
    public void sayHello() {
        super.sayHello();
    }
    public void sayGoodbye() {
    }
}

public class VirtualMethodTable {
}


10、方法返回地址

保存进入方法的指令地址,在方法结束后返回这个地址,执行后续代码

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

package com.atguigu.java3;

import java.io.FileReader;
import java.io.IOException;
import java.util.Date;

/**
 *
 * 返回指令包含ireturn(当返回值是boolean、byte、char、short和int类型时使用)、
 * lreturn、freturn、dreturn以及areturn,另外还有一个return指令供声明为void的方法、
 * 实例初始化方法、类和接口的初始化方法使用。
 *
 * @author shkstart
 * @create 2020 下午 4:05
 */
public class ReturnAddressTest {
    public boolean methodBoolean() {
        return false;
    }

    public byte methodByte() {
        return 0;
    }

    public short methodShort() {
        return 0;
    }

    public char methodChar() {
        return 'a';
    }

    public int methodInt() {
        return 0;
    }

    public long methodLong() {
        return 0L;
    }

    public float methodFloat() {
        return 0.0f;
    }

    public double methodDouble() {
        return 0.0;
    }

    public String methodString() {
        return null;
    }

    public Date methodDate() {
        return null;
    }

    public void methodVoid() {

    }

    static {
        int i = 10;
    }


    //
    public void method2() {

        methodVoid();

        try {
            method1();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void method1() throws IOException {
        FileReader fis = new FileReader("atguigu.txt");
        char[] cBuffer = new char[1024];
        int len;
        while ((len = fis.read(cBuffer)) != -1) {
            String str = new String(cBuffer, 0, len);
            System.out.println(str);
        }
        fis.close();
    }


}

11、一些附加信息

在这里插入图片描述

12、虚拟机栈相关面试题

在这里插入图片描述

在这里插入图片描述


package com.atguigu.java3;

/**
 * 面试题:
 * 方法中定义的局部变量是否线程安全?具体情况具体分析
 *
 *   何为线程安全?
 *      如果只有一个线程才可以操作此数据,则必是线程安全的。
 *      如果有多个线程操作此数据,则此数据是共享数据。如果不考虑同步机制的话,会存在线程安全问题。
 * @author shkstart
 * @create 2020 下午 7:48
 */
public class StringBuilderTest {

    int num = 10;

    //s1的声明方式是线程安全的
    public static void method1(){
        //StringBuilder:线程不安全
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        //...
    }
    //sBuilder的操作过程:是线程不安全的
    public static void method2(StringBuilder sBuilder){
        sBuilder.append("a");
        sBuilder.append("b");
        //...
    }
    //s1的操作:是线程不安全的
    public static StringBuilder method3(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        return s1;
    }
    //s1的操作:是线程安全的
    public static String method4(){
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
        return s1.toString();
    }

    public static void main(String[] args) {
        StringBuilder s = new StringBuilder();


        new Thread(() -> {
            s.append("a");
            s.append("b");
        }).start();

        method2(s);

    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值