JVM内存模型
2022-09-13 15:47:18 0 举报
jvm内存模型图,涉及类加载、堆内存、JVM参数调优等内容
作者其他创作
大纲/内容
字节码校验器会检查生成的字节码是否正确,如果验证失败则会验证错误
1/10
加载
线程隔离的数据区
垃圾回收算法:标记清除、复制(多为新生代垃圾回收使用)、标记整理
即时编译器JIT Compiler
新生代(Young Generation,满了促发Young GC)
线程N
1、JVM年轻代垃圾回收算法?对象什么时候转移到老年代? 如果说你让代码一边运行,一边有变动,一边判断哪些对象是可以回收的,这个是不现实的,垃圾回收的时候有一个概念,叫做stop the world,停止你的jvm中的工作线程,然后扫描所有的对象,判断哪些可以回收,哪些不可以回收。 年轻代在大部分情况下,对象的生命周期很短的,可能在0.01ms之内,比如线程执行了3个方法,创建了几个对象,0.01ms之后方法执行结束了,此时那几个对象就变成了垃圾可以回收的。 复制算法,YGC存活对象会被复制到一块survivor区,并清空其余垃圾对象;对象在S区熬过了很多次垃圾回收(15)转移到老年代什么情况下对象会进入老年代: 长期存活的对象(S区存活15次) 垃圾回收时S区放不下的对象 特别大对象
-XX:MetaspaceSize=512M-XX:MaxMetaspaceSize=1024M
MetaData
识别
1
To
垃圾收集器
Survivor Space
4
From
Custom自定义类加载器
Extension类加载器
应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader
加载$JAVA_HOME/jre/lib/rt.jar里所有的class,不是ClassLoader子类
直接内存
类或接口的初始化由执行类或接口初始化方法构成。这里所有的静态变量与原来的值将被指派,静态块将被执行
1/3 堆空间
探测分析器
老年代(Old Generation,满了促发Full GC)
连接
类装载子系统
本地方法库
中间代码生成器
代码优化器
运行时数据区
Method Area方法区(持久代)JDK8中已经使用Metaspace元数据区完全取代了永久代(即方法区),而且元数据区不在JVM中,而是使用本地内存,默认情况下受操作系统内存限制
GC
本地方法接口JNI
所有线程共享的数据区域
1、parnew(年轻代多线程回收) + CMS(老年代) CMS分为好几个阶段,初始标记、并发标记、并发清理,等等。老年代垃圾回收是比较慢的,一般起码比年轻代慢个10倍以上;CMS刚开始用标记-清理,标记出来垃圾对象,清理掉垃圾对象,之后整理,把一些存活对象压缩到一起,避免内存碎片的产生; 执行一个比较慢的垃圾回收,还要stop the world,加入需要100ms,此时系统就会停顿100ms不能处理任何请求,尽可能的让垃圾回收和工作线程并行执行2、G1直接分代回收,新版本(jdk11 ..12...)慢慢的主推g1垃圾回收器了,以后会淘汰掉parnew+cms组合;但是目前主流还是jdk8,parnew+cms的组合比较多一些
2、堆内存空间
每个线程必须分开程序计数器登记。当前执行的指令一旦执行,程序计数器更新下一个指令。一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器。
收集和删除未引用的对象,可以通过调用System.gc()促发垃圾收集,但不能保证执行。JVM的垃圾收集对象是已创建的对象。
[-Xmn: 设置新生代堆大小]
Navive Method Stack本地方法栈
存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
Application类加载器
解释器
Eden
生产环境设置JVM参数,检查JVM运行情况
字节码文件(.class文件)
2
目标代码生成器
在虚拟机启动的时候创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都是在这里分配内存。存储的数据不是线程安全的,堆和常量池空间不足则会引发OutOfMemoryError
对于Java Web系统,JVM进程对应的是tomcat,你的系统仅仅实在tomcat的jvm进程里执行;对与jvm参数,可以在tomcat的配置脚本catalina里找一下。对于通过Java命令直接启动一个main方法跑起来的系统,就是你自己启动的时候,Java命令可以带上一些JVM参数: 内存区域大小分配:每个线程的栈大小,元空间大小,堆内存大小,年轻代和老年代分别的大小,eden区和survivor区域分别大小是多少。如果没有甚至,会有一些默认值(jvm专栏) 垃圾回收器:年轻代老年代分别用的什么垃圾回收器,每种垃圾回收器是否对应一些特殊的参数,那些特殊的参数分别都是用来干什么的。 为什么要这么设置?当前系统运行的时候,jvm的表现如何?可以看救火队队长的《从0开始带你成为jvm实战高手》专栏,有大量的实战案例讲解。在一定的业务背景下,如何进行系统运行时的对象数量的预估,对内存的压力进行预估,对整个jvm运行的状况进行预估;然后根据预估情况设置一些jvm参数。 进行压测,在压测的时候,尤其需要观察JVM的运行情况,jstat工具去分析JVM运行的情况,它的年轻代里eden区域对象的增长情况,ygc的频率,每次ygc过后有多少对象存活,s区能否放得下,老年代对象增长速率,老年代多久会促发一次fgc; 根据压测结果进行jvm参数调优,一个系统的QPS,接口的性能,压测到一定程度的时候,机器的cpu、内存、io、磁盘的一些负载情况、JVM的表现。可能需要对代码进行优化,比如优化性能,或者减轻一些cpu负担,减轻io和磁盘负担,发现jvm的gc过于频繁,内存泄漏,此时就需要对jvm的各个内存区域大小以及一些参数进行调优。 跑到线上生产环境中去,运行的过程,也需要基于一些监控工具,或者是jstat;观察系统的QPS和性能,接口可用性,调用成功率,机器的负载,jvm表现,gc的频率,gc耗时,内存的消耗。
对于所有静态变量的内存分配和默认值分配
加载classpath中指定的jar包及目录中的class
[ -Xms:设置最小堆空间、-Xmx:设置最大堆空间 ]
JNI将与本机方法库进行交互,并提供执行引擎所需的本机库
准备
1、JVM内存模型
Bootstrap类加载器
8/10
初始化
2、说说老年代垃圾回收算法,常用的垃圾收集器是什么 老年代对象越来越多,内存空间也会满的,可不可以使用类似年轻代的复制算法?不合适的,因为老年代里的对象很多是被长期引用的,比如spring容器管理的各种bean。长期存活的对象时比较多的,可能甚至有几百MB,复制来复制去是不划算的。 对于老年代而言,它里面的垃圾对象可能是没有那么多的。使用标记-清理算法,找出哪些垃圾对象,然后直接清除掉,但是会出现内存碎片问题。标记-整理算法,把老年代存活的对象标记出来,移动到一起,存活对象压缩到一片内存空间里去,剩余的空间都是垃圾对象整个给清理掉,这样保证剩余的空间是连续可用的。
3
通过类装载器装载的,被分配到JVM的运行时数据区的字节码会被执行引擎执行。执行引擎以指令为单位读取Java字节码。它就像一个CPU一样,一条一条的执行机器指令。每个字节码指令都由一个一字节的操作码和附加的操作数组成。执行引擎取得一个操作码,然后根据操作数来执行任务,完成后就继续执行下一条操作码。
heap 堆
Java执行引擎
每一个线程创建一个单独的运行时堆栈,对于每一个方法调用,一个称为栈内存栈帧被创建。所有局部变量将被创建在栈内存中。栈内存是线程安全的,因为它不是一个共享资源。与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期与线程相同。栈空间用光了会引发StackOverFlowError
VM Stack虚拟机栈
Program Counter Register程序计数器
PermGen
加载Java平台中扩展功能的一些jar包,包括$JAVA_HOME/jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包
与虚拟机栈所发挥的作用是十分相似的。其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的native方法服务。
Java堆、GC堆
Tenured Space
验证
解析或识别是从运行时常量池的符号引用中动态具体值的过程
JDK1.8后,永久代被移除由元空间替换。
排查线上系统OOM问题:狸猫技术窝公众号里的救火队队长的《从0开始带你成为jvm实战高手》 oom可能发生在哪几个区域,解决的一个思路,在jvm里可以设置几个参数,如果一旦jvm发生了oom之后,就会导出一份内存快照,就会有当时的线上内存里的对象的一个情况,可以用MAT这样的工具,可以去分析 无非就是找出来当时的时候占用内存最大的对象都是谁,找出来那些对象是在代码中哪些地方创建出来的,一般来说就是可能会对内存去做一个调优 还是得去参考jvm专栏里的大量的案例背景,从业务背景出发,一步步去说明,在什么样的业务背景之下,为什么会产生oom的问题呢?必然会导致系统可能就是崩溃了,客服会反馈说,XX功能不能用了,说某个系统崩溃了 找他自动导出的内存快照,分析,XX对象,直接去定位代码,修改代码 你一定要把案例的业务、背景和思想给吸收了,就得融入到自己的业务里去,我负责的业务系统,在什么样的情况下,可能说会出现一大批的对象卡在内存里,无法回收,导致我系统没法放更多的对象了 产生OOM,内存泄漏的问题,少数场景在互联网公司,超高并发下的oom问题,瞬时大量存活对象占据内存, 导致没法创建更多的对象了 你也得去思考,甚至去模拟一下,最好可以模拟出来,oom不是你自己的代码,可能是你依赖的第三方的组件,netty导致的,结合自己的项目去一步一步的分析,oom问题的产生,和解决的过程
0 条评论
下一页