5.运行时数据区-字符串常量池、程序计数器、直接内存

目录

  • 概述
  • 字符串常量池
    • 字符串常量池存储数据的方式
      • 三种常量池
      • 字面量与符号引用
    • 哈希表
    • 实战
  • 程序计数器
  • 直接内存
    • 直接内存与堆内存比较
  • 结束

概述

相关文章在此总结如下:

文章 地址
jvm基本知识 地址
jvm类加载系统 地址
双亲委派模型与打破双亲委派 地址
运行时数据区 地址

字符串常量池

字符串常量池存储数据的方式

字符串常量池使用的是StringTable的数据结构存储数据,类似于HashTable(哈希表)

注意: 双引号表示的字符串,默认都是存在字符串常量池的。堆内存中的字符串想进入字符串常量池,也不是不可的。

5.运行时数据区-字符串常量池、程序计数器、直接内存_第1张图片

三种常量池

  • Class文件常量池
  • 运行时常量池
  • 字符串常量池

字面量与符号引用

字面量: int 、float、long、double、双引号字符串等
符号引用:Class、Method、Field等

哈希表

哈希表(也叫散列表),是根据关键码值(K-V)而直接进行访问的数据结构。本质上就是个数组+链表

5.运行时数据区-字符串常量池、程序计数器、直接内存_第2张图片

  • key:散列函数,公式:hash(字符串) % 数组size
  • value:字符串的引用
  • size: -XX:StringTableSize=65536
    目标:加速查找速度

实战

测试案例如下:

package com.fun.classloader;

/**
 * 测试字符串常量池
 */
public class TestStringPool {
    public static void main(String[] args) {
        test();
    }

    public static void test() {
        String str1 = "abc";
        String str2 = new String("abc");
        // false  == 比较的是对象内存地址
        System.out.println(str1 == str2);

        String str3 = new String("abc");
        // false
        System.out.println(str2 == str3);

        // 编译期会计算出 "ab"
        String str4 = "a" + "b";
        // true
        System.out.println(str4 == "ab");

        String s1 = "a";
        String s2 = "b";
        String str6 = s1 + s2;
        // false 变量相加运行期计算
        System.out.println(str6 == "ab");

        // 带方法的运算也是运行期计算
        String str7 = "abc".substring(0, 2);
        // false
        System.out.println(str7 == "ab");

        String s5 = "a";
        String s6 = "abc";
        String s7 = s5 + "bc";

        // true
        System.out.println(s6 == s7.intern());
    }
}

5.运行时数据区-字符串常量池、程序计数器、直接内存_第3张图片

总结如下:

  • 单独使用""引号创建的字符串都是常量,编译期就已经确定存储到字符串常量池中
  • 使用 new String(“”) 创建的对象会存储到 heap 中,是运行期新创建的
  • 使用只包含常量的字符串连接符,如:“a”+“b” 创建的也是常量,编译期就已经确定存储到字符串常量池中
  • 使用包含变量的字符串连接如 “a” + s 创建的对象是运行期才创建的,存储到 heap 中
  • 运行期调用 String 的 intern() 方法可以向字符串常量池中动态添加对象

程序计数器

程序计数器,也叫PC寄存器、当前线程所执行的字节码指令行号指示器

**注意:**线程切换(系统上下文切换) 后准确恢复执行位置,需要知道执行到的位置

存储数据

  • java 方法:记录虚拟机字节码指令地址
  • native方法:记录为空

异常:唯一没有OOM异常的区域

直接内存

直接内存不是虚拟机运行时数据区的一部分,也不是 java 虚拟机规范 中定义的内存区域

在 jdk1.4 中,新加了 NIO,引入了 Channel 和 Buffer 的 IO 方式,可以使用 native 方法直接分片对外内存,然后通过 DirectByteBuffer 对象可以操作直接内存。

直接内存与堆内存比较

内存区域 分配空间 读写操作
堆内存 性能很好 效率低
直接内存 性能很差 效率高

结束

至此,字符串常量池、程序计数器、直接内存,就结束了,如有疑问,欢迎评论区留言。

你可能感兴趣的:(jvm,jvm,运行时数据区,字符串常量池,程序计数器,直接内存)