当前位置: 首页 > news >正文

JVM内存模型剖析

类加载子系统:编译后的字节码是在磁盘中,通过类加载子系统将磁盘中的字节码读取到内存中,比如放到方法区后,字节码指令由执行引擎中的解释器,执行方法区中的字节码。

JIT解释器:热点字节码指令需要经常执行,我们就可以把该字节码指令缓存起来,通过JIT编译器将热点的字节码指令,提高执行效率。

线程共享区:

        堆:JVM中规范所有的对象和数组都应该存放在堆中,在执行字节码指令时,会把创建的对象存入堆中,对象对应的应用地址存入虚拟机栈中的栈帧,方法执行完后,创建的对象不会立刻被回收,而是要等JVM后台执行GC,对象才会被回收。

        方法区(概念):存放线程执行的方法,JDK8采用永久代实现,归属于堆的一部分,JDK8后迁移出堆归属于系统内存改元空间实现。

线程私有区:

        虚拟机栈:每个线程运行所需要的内存,每个栈由多个栈帧(Frame)组成,对应着每次方法的调用,每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。

        本地方法栈:native修饰的,JVM中使用C/C++写的一些方法。

        程序计数器:线程中发生的切换时保存下一次需要执行的指令位置。即下一条预执行指令的地址。

栈帧:局部变量表+方法出口+操作数栈+动态链接

操作数栈:执行字节码期间进行变量运算和操作

局部变量表:存储方法参数和局部变量

动态链接:将符号引用转换为直接引用

方法出口:保存方法返回后需要继续执行的地址。

步骤:

1.加载:找到class文件,将磁盘上的class文件加载到内存中

2.验证:校验class文件格式问题

3.准备:为常量静态变量分配内存设置零值

4.解析:解析符号引用(System、String),将全限定类名解析为实际的类

5.初始化:执行静态代码块,显示赋值静态变量

6.执行main方法:创建对象,调用方法

双亲委派流程:

public class ParentDelegation {

    // 加载类的流程:

    // 1. 当前类加载器检查是否已加载

    // 2. 未加载则委托给父类加载器

    // 3. 父类加载器重复此过程,直到启动类加载器

    // 4. 父类加载器无法加载时,才由子类加载器尝试加载

}

细说运行时数据区:

栈溢出:

1.不断产生栈帧。   递归调用

2.栈帧过大。    这种情况很少。

线程诊断:1.cpu占用过高    linux中用top定位哪个进程cpu占用过高,再用ps H -eo pidtid%cpu  | grep 进程id进一步定位   jstack  线程id  id转成16进制排查

2.线程长时间运行无结果    死锁,jstack  线程id   同上排查。

堆溢出:不断创建对象,但是又没有当成垃圾回收。  如不断往集合中添加对象。可以通过Xmx设置大小。

诊断工具:

1.jps工具:查看当前系统有哪些java进程     2.jmap工具:查看堆内存占用情况  jmap  -heap  进程ID   3.jconsole工具:图形界面监测工具  4.jvirsualvm图形化诊断页面

新生代:存放新创建出来的对象。老年代:存放多次GC后仍存活的对象。

新创建出来的对象存放在新生代的Eden区,当Eden区快满时触发MinorGC(新生代垃圾回收)通过垃圾回收算法回收掉标记的垃圾对象空闲出空间,再把存活下来的对象迁移到S0区并标记分代年龄,随着迁移S0区的对象变多,也会满,就会在S0区也触发MinorGC将存活的对象迁移到S1区,就这样,存活的对象在S0和S1区经过MinorGC来回迁移,到达分代年龄的阈值(默认15)后就会迁移到老年代中。

对于新创建出来的对象如果S0,S1区存放不了,可能在Eden区经历一次YGC直接存放到老年代中,对于Eden区也存放不了的则直接存入老年代中。

方法区:

JDK1.7前采用永久代实现,位于堆内,JDK8后采用元空间实现,位于堆外(本地内存)。

为什么要改变实现方式?

永久代:

1.受到JVM堆大小限制  2.垃圾回收效率低,基本FullGC和老年代一起回收。3.调优需要平衡堆和永久代大小。

元空间:1.性能提升,减少FullGC次数。2.效果回收垃圾,与GC堆分离,有专门的类加载回收。

这种变化是为了解决永久代内存限制和性能问题。

运行时常量池:位于元空间中,存储符号引用和直接引用,各种常量,类和接口的符号引用,字段和方法的符号引用,属于编译期。

字符串常量池:位于堆中,缓存字符串字面量,实现字符串复用机制,属于运行期。

JDK1.6前,运行时常量池包含了字符串常量池,JDK8后,运行时常量池迁移到堆中,而运行时常量池位于本地内存。两者是引用关系,当常量池中需要用到串池中的字面量时通过引用找到串池检查是否存在,存在复用,不存在新建。

字符串常量池特性(StringTable):

1.拼接原理是StringBuilder(jdk8)

2.字面量自动入池,动态字符串手动调用intern

3.复用机制,减少内存占用

4.固定大小的哈希表,解决冲突哟个链表

5.JDK7+位于堆中,受GC管理。

JDK6时,StringTable是常量池的一部分,存储在永久代中,JDK7后转移到堆中,因为永久代内存回收率低。

http://www.dtcms.com/a/442092.html

相关文章:

  • 山东网站制作哪家好网站优化方案和实施
  • 工作中使用到的单词(软件开发)_第五版
  • Vue3 Router高级用法—菜单动态渲染
  • 西安seo网站排名优化公司网站快速推广排名技巧
  • LeetCode算法日记 - Day 62: 黄金矿工、不同路径III
  • 济南建设工程信息网站asp.net实用网站开发
  • deepseek 的对话json导出成word和pdf
  • php 网站 项目如何用wordpress搭建个人博客
  • Prometheus监控K8S集群-ExternalName-endpoints-ElasticStack采集K8S集群日志实战
  • 解读DeepSeek-V3.2-Exp:基于MLA架构的Lightning Index如何重塑长上下文效率
  • 视频网站开发公司有哪些公司国家新闻出版
  • GitHub 热榜项目 - 日榜(2025-10-04)
  • datawhale RAG技术全栈指南 202509 第6次作业
  • 电影网站建设成本百怎么做网站
  • e语言可以做网站吗西安网站建设 翼驰
  • Redis 热点数据与冷数据解析
  • 【计算机视觉】车牌分割定位识别
  • wordpress做网站容易吗用lls建设一个网站
  • 从 3.6 亿订单表到毫秒级查询:分库分表指南
  • 网站怎样设计网页做黄金期货的网站
  • 无线网卡——WIFI7无法在Ubuntu22.04系统中使用
  • Ubuntu20.04下的Pytorch2.7.1安装
  • MySQL:C语言链接
  • 合肥市门户网站中国纪检监察报社长
  • 黑马点评秒杀优化和场景补充
  • 嵌入式硬件——基于IMX6ULL的UART(通用异步收发传输器)
  • Spark Shuffle:分布式计算的数据重分布艺术
  • 网站能看出建设时间吗网页设计工资统计
  • Postgres数据库truncate表无有效备份恢复---惜分飞
  • 【邪修玩法】如何在WPF中开放 RESTful API 服务