JVM内存结构

JVM内存结构

Java代码执行流程:

java源代码 -> jvm指令 -> 二进制字节码 -> 解释器 -> 机器码 -> CPU

1.程序计数器

作用: 记录下一条jvm指令的执行地址

如果没有程序计数器 程序就不知道下一条该执行什么指令了

物理上:就是寄存器

特点:

  • 是线程私有的
  • 不会存在内存溢出

2.虚拟机栈

栈:线程运行需要的内存空间

栈帧:每个方法运行时需要的内存 (参数、局部变量、返回地址)

定义

  • 每个线程运行时所需要的内存,称为虚拟机栈
  • 每个栈由多个栈帧组成,对应着每次方法调用是所占用的内存
  • 每个线程只能有一个活动帧,对应着当前正在执行的那个方法

内存溢出

  • 栈帧过多导致栈内存溢出
  • 栈帧过大导致栈内存溢出

常见问题

1. 垃圾回收是否涉及栈内存?

不涉及,垃圾回收只会回收堆内存中的数据

2.栈内存分配越大越好吗?

栈内存分配的大反而会让线程数变少,一般使用系统默认的就可以

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

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

3.本地方法栈

给本地方法的运行提供内存空间

native:底层是用C/C++写的 用于java更方便的调用

4.堆

堆(Heap)

  • 通过new关键字,创建对象都会使用堆内存

特点

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

堆内存溢出

虽然有垃圾回收机制,但是堆内存也会溢出。比如对象不能在try块里面循环就不能被回收,导致内存溢出。

5.方法区

定义

  • 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。
  • 它存储已被Java虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。

特点

  • 方法区是线程共享的,多个线程都用到一个类的时候,若这个类还未被加载,应该只有一个线程去加载类,其他线程等待。
  • 方法区的大小可以是非固定的,jvm可以根据应用需要动态调整,jvm也支持用户和程序指定方法区的初始大小。
  • 方法区有垃圾回收机制,一些类不再被使用则变为垃圾,需要进行垃圾清理。

常量池

常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息

运行时常量池,常量池是*.clss文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

StringTable(串池)

每个定义一个String对象 如String s = "a"; 首先会去串池中找这个对象,如果串池中没有,就给加进串池中,如果有就用里面的。

看一下常见题目

String s1 = "a"; //串池中找,如果没有则加入
String s2 = "b"; //同上
String s3 = "ab"; //同上
String s4 = s1 +s2; //变量是不确定的需要 new String("ab") --- new StringBuilder().append("a").append("b").toString()
String s5 = "a" + "b"; //都是确定的常量,就不需要new对象 属于编译器的优化
String s6 = s4.intern();//会将动态生成的堆中的对象放入串池
System.out.println(s3 == s4); //false
System.out.println(s3 == s5); //true
System.out.println(s3 == s6); //true
String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();
System.out.println(x1 == x2); //false 因为串池中有对象 所以intern就没有把对象放入串池

特性总结

  • 常量池中的字符串仅是符号,第一次用到时才变为对象
  • 利用串池的机制,来避免重复创建字符串对象
  • 字符串变量拼接的原理是StringBuilder(1.8)
  • 字符串常量拼接的原理是编译期优化
  • 可以使用intern方法,主动将串池中还没有的字符串对象放入串池
    • 1.8将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回
    • 1.6将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池,会把串池中的对象返回

存放位置

1.6存放在方法区永久代中,1.7之后存放在堆中

垃圾回收机制

当内存不足时,字符串常量也会被垃圾回收

性能调优

  • 调整-XX:StringTableSize=桶个数
  • 考虑将字符串对象是否入池

6. 直接内存

不属于java虚拟机内存 是操作系统内存

定义

  • 常见NIO操作时,用于数据缓冲区
  • 分配回收成本较高,但读写性能高
  • 不受JVM内存回收管理

会产生内存溢出,可以使用了unsafe对象完成直接内存的分配回收,并且回收需要主动调用freememory方法。

posted @   Cloong  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示