关于JVM内存模型的相关介绍与简单实战

发布时间:2023年12月21日

JVM类加载机制

类加载运行全过程
  • 加载:从磁盘读取字节码文件加载到内存中
  • 验证:验证字节码文件的正确性
  • 准备:给类的静态变量分配内存,并赋予默认值,比如int类型设置为0,String类型设置为null
  • 解析: 1)、将符号引用替换为直接引用,类名,静态方法名刚开始都叫做符号。解析过程将这些符号转为内存地址的直接引用(静态链接,类加载期间完成)
    2)、动态链接(不解析),比如类中方法的调用,在类加载的时候不会解析,直到运行的时候会去动态获取
  • 初始化:静态变量赋予指定的值。

类加载器

  • 引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar
  • 扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR包类
  • 应用类加载器:负责加载classpath下的类,自己写的那些类的加载

JVM内存模型深度剖析与优化

在这里插入图片描述

存放对象,也是发生线程安全的地方
在这里插入图片描述
new对象分配在Eden区间

  • Eden区满了就开始minor GC,也叫young GC
  • 通过根可达算法去寻找GC root,
  • 所有可找到根的一系列引用程序都不是垃圾对象会移动到survive区分代年龄加一。当分代年龄超过15会移动到老年代

老年代

  • 对象类型:静态变量、缓存对象、spring容器里面的对象都有可能移动到这边
  • 老年代放满的情况触发full GC。如果回收不了就会报OOM

STW(stop the world)

  • 在执行GC的时候会线程会暂停一段时间
  • jvm调优的目的就是平衡STW和GC的频繁程度
  • GC过程中为什么要STW,为了防止找垃圾对象时发生混乱

线程独立内存空间,局部变量存放位置。不同线程有自己独立的内存空间
栈帧: 一个方法对应一个独立的栈帧空间
局部变量表

存放局部变量,类似数组结构
局部变量如果new 对象。对象是存在堆空间。局部变量表存放内存的引用地址

操作数栈

是一个数据在操作时临时存放的内存空间。也是一个栈结构

动态链接

程序在加载的时候才能确认一些调用,所以有些接口的调用是动态的。

方法出口

记录方法进入时的位置,在方法调用结束返回。

-xss设置单个栈的空间大小(一个线程)
理论上:单个栈的空间分配越少,能开的线程就越多。其他影响的因素还有句柄数等信息

元空间

元空间的内存是外部内存。方法区就是在元空间。元空间的初始大小是21MB

-XX:MetaSpaceSize指定元空间的初始空间大小,默认是21M,达到该值就会触发full GC进行类型卸载
同时收集器会对该值进行调整;如果释放了大量的空间,该值就会调低;如果释放了很少的空间,那么在不超过
-XX:MaxMetaSpaceSize的情况下适当提高该值。由于调整元空间大小需要触发Full GC,这是非常昂贵的操作,如果应用
在启动的时候触发大量Full GC,通常是由于永久代或是元空间发生了调整,基于这种情况,一般建议在JVM参数中将MetaSpaceSize和MaxMetaSpaceSize设置成一样,并设置得比初始值要大。对于8G的物理内存我们一般设置256MB

程序计数器

记录程序执行的指针的位置,程序的内存地址
程序执行引擎会根据代码执行的进度修改计数器。程序计数器存在的意义在于多线程切换时能记录下来程序执行的位置。

JVM内存分配机制深度剖析

内存分配机制

1、对象动态年龄判断机制
当前放对象的Survivor区域里(其中一块区域,放对象的那块s区),一批对象的总大小大于这块Survivor区域内存大小的50%(-XX:TargetSurvivorRatio可以指定),那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了。例如Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Sruvivor区域的50%,此时就会把年龄n(含)以上的对象都放到老年代,这个规则其实是希望那些可能长期存活的对象,今早进入老年代。对象动态年龄判断机制一般是在minor gc之后触发的。
2、老年代空间分配担保机制
在做minor gc 之前会进行校验,老年代剩余的空间是否能放下所有
在这里插入图片描述

例子详解

业务场景

支持每秒1000的订单,一共3台机器 4核8G。均分到每台上需要承担300左右的并发
内存估算
订单对象每个差不多1KB,每秒差不多300KB订单对象。下单还涉及其他对象,如库存、优惠价卷、积分等,我们放大20倍。(300KB*20)/秒对象生成,每秒差不多300KB订单对象。可能同时还有其他操作,如订单查询等,我们再放大10倍。每秒产生60M的对象,差不多一秒以后都变为垃圾对象
初始jvm参数设置
老年代:年轻代 默认2:1

java -Xms3072M -Xmx3072M -Xss1M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M -jar microservice-eureka-server.jar

初始内存模型
在这里插入图片描述
因为幸存区太小,触发动态年龄判断机制,会往老年代放。导致触发fullGC
调整jvm参数,提高年轻代内存

java -Xms3072M -Xmx3072M -XmN2048m -Xss1M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M -jar microservice-eureka-server.jar

调整后的内存模型
在这里插入图片描述
避免引起空间担保机制

后续更新JVM实战常用命令的使用

文章来源:https://blog.csdn.net/qq_42207682/article/details/135090365
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。