JVM内存结构(从字节码分析字符串常量池)


内存结构

在这里插入图片描述

程序计数器

Program Counter Register 程序计数器(寄存器)

作用:是记住下一条jvm指令的执行地址特点

  • 是线程私有的,一个线程一个程序计数器。线程的嵌套调用就依赖于程序计数器。
  • 不会存在内存溢出

虚拟机栈

Java Virtual Machine Stacks (Java 虚拟机栈)

方法运行时使用的内存,比如main方法运行,进入方法栈,存放方法中的局部变量

每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。栈中可执行的方法数量是有限的,不停的递归调用方法,可能会造成栈内存溢出。但是并不是栈内存越大越好,栈内存大了,相应的能创建的线程就会减少。

方法内的局部变量是否线程安全?

  • 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
  • 如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

本地方法栈

调用本地方法(native),为本地方法提供的内存空间
本低方法:非java语言写的代码 不同操作系统,本地方法不同

例: clone() hashcode() notify()

Heap 堆

通过 new 关键字,创建对象都会使用堆内存,成员变量都在堆内存
jdk7之后,字符串常量池也在堆内存中

特点

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

常用诊断工具

  1. jps 工具
    查看当前系统中有哪些 java 进程
  2. jmap 工具
    查看堆内存占用情况 jmap - heap 进程id
  3. jconsole 工具
    图形界面的,多功能的监测工具,可以连续监测
  4. visualvm工具(jdk8以后需要自己下载)
    visualvm下载安装

方法区

储存可以运行的class文件,包含方法的信息,静态区,成员方法

内存结构
jdk1.6 永久代
在这里插入图片描述
jdk1.8元空间
在这里插入图片描述

常量池

  • (静态)常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量
    等信息
  • 运行时常量池,常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

字符串常量池

底层是hash表

  • 常量池中的字符串仅仅是符号,第一次用到才会变为对象
  • 字符串变量拼接
  • 字符串常量拼接,编译期优化
  • 可以使用intern方法,将串池中还没有的数据放入到串池。
    • jdk1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
    • 1.6 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回

从字节码的角度分析,jdk9

 @Test
    public void test01(){
    
    
        String s1 = "a";
        String s2 = "b";
        String s5 = "ab";
        String s3 = s1+s2;
        String s4 = "a"+"b";
    }

反编译命令javap -v 文件名.class

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ren9436/article/details/108905431