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方法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了