JVM组成结构
1.程序计数器(Program Counter Register)
作用:记住下一条jvm指令的执行地址
特点:1.线程私有:每个线程有一个独立的程序计数器,随线程创建而创建,随线程结束而死亡。
2.无内存溢出(OutOfMemoryError):在编译时已经确定该线程代码的偏移量最大值,不会出现内存溢出
3.①执行java方法,计数器记录虚拟机字节码指令的地址;②执行native方法,计数器为空
2.虚拟机栈(Java Virtual Machine Stacks)
2.1定义
每个线程运行时所需要的总内存,被称为虚拟机栈。
每个栈有多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存。
每个线程只有一个活动栈帧,对应着当前正在执行的那个方法。
回答:
1.不涉及,GC主要针对的是堆空间的内容。
2.栈内存越大,总内存不变的情况下,栈(线程)总数目越少。
3.(1)如果局部变量没有逃离方法的作用范围,则是线程安全的。
(2)如果局部变量引用了对象,并逃离方法的作用范围,则需要考虑线程安全。(逃逸行为)
2.2栈内存溢出
1.**栈帧过多**导致栈内存溢出
2.**栈帧过大**导致栈内存溢出
2.3线程运行诊断
案例1:cpu占用过多
定位:
- 用top定位哪个进程对cpu的占用过高
- ps H -eo pid,tid,%cpu | grep 进程id (用ps命令进一步定位是哪个线程引起的cpu占用过高)
- jstack 进程id(可以根据线程id找到有问题的线程,进一步定位到问题代码的行处)
Tips:pid、tid分别为process id和thread id,nid为 Native Thread id(系统线程)
案例2:程序运行很长时间没有结果
3.本地方法栈(Native Method Stack)
为了与操作系统底层进行交互,引入了一些用c/c++编写的方法——用关键字 native 修饰
本地方法栈:为本地方法的运行提供内存空间
4.堆(Heap)
4.1定义
通过new关键字,创建对象都会使用堆内存。
特点:
它是线程共享的,堆中对象都需要考虑线程安全的问题。
有垃圾回收机制(GC)。
4.2堆内存溢出
4.3堆内存诊断
1.jps工具:查看当前系统中有哪些java进程
2.jmap工具:查看堆内存占用情况(某时刻)jmap -heap 进程id
3.jconsole工具:图像界面的,多功能的监测工具,可以连续监测
4.jvisualVM工具:jconsole增强版
案例:
垃圾回收后,内存占用仍然很高
5.方法区(Method Area)
5.1定义
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。
它存储已被Java虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。
5.2特点
1.方法区是线程共享的,多个线程都用到一个类的时候,若这个类还未被加载,应该只有一个线程去加载类,其他线程等待;
2.方法区的大小可以是非固定的,jvm可以根据应用需要动态调整,jvm也支持用户和程序指定方法区的初始大小;
3.方法区有垃圾回收机制,一些类不再被使用则变为垃圾,需要进行垃圾清理。
5.3方法区内存溢出
1.6以前会导致永久代内存溢出
1.8以后会导致元空间内存溢出
5.4运行时常量池
1.8以前方法区包含StringTable,1.8以后将运行时常量池划给了堆
常量池,就是一张表,虚拟机指令根据这张常量池表找到要执行的类名、方法名、参数类型、字面量等信息
运行时常量池,常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)