JVM学习一

简介: jvm的内存结构:可以看到我们的java文件会首先编译成class文件,经过类加载器进行加载,然后经过jvm的相关区域:f方法区、堆、虚拟机栈、程序计数器、本地方法栈等地,可以进行本地方法接口进行调用,执行引擎,进行编译,执行程序。当中涉及到垃圾回收。

JVM学习一

jvm的内存结构、相关的垃圾算法、分代回收算法、相关溢出的问题排查思路

微信图片_20221214013109.jpg

jvm的内存结构:可以看到我们的java文件会首先编译成class文件,经过类加载器进行加载,然后经过jvm的相关区域:f方法区、堆、虚拟机栈、程序计数器、本地方法栈等地,可以进行本地方法接口进行调用,执行引擎,进行编译,执行程序。当中涉及到垃圾回收。

1.程序计数器:Program Count Register

寄存器,记住下一条jvm指令的执行地址,是线程私有的,JVM中唯一不会存在内存溢出的。

2.虚拟机栈:Java Virtual Mechinal Stacks

每个线程只能有一个活动栈帧,通常是参数、局部变量、返回地址,对应着当前正在执行的那个方法

栈帧:每个方法运行时需要的内存。

垃圾回收设计栈内存吗?不涉及栈内存。

栈内存的分配越大越好吗?

不是的,通常是默认的,1024k,其中linux和mac电脑默认是1024k,而windows是根据系统而定。由于一个线程对应一个栈帧,如果越大,则会拖慢虚拟机的运行性能。

方法内的局部变量是否线程安全?

如果方法内的局部变量没有逃离方法的作用访问,则它是线程安全的,如果局部变量应用了对象,并逃离方法的作用范围,则需要考虑线程安全的问题。也即与变量的作用域有关。

栈内存溢出:栈帧过多、过大都会导致栈内存溢出。

栈内存溢出的排查方法:

首先采用top命令,查看当前是哪个进程cpu占用过高

接着采用ps H -eo pid,tid,%cpu |grep 进程id

用jstack 进程id排查到有问题线程,定位到问题代码的行号,从而解决问题。

3.本地方法栈:Native Method Stacks

主要存放操作系统的方法,存放native方法的内存调用。

4.堆:Heap

通过new关键字创建的对象都会被存放在堆内存中。它是线程共享的,堆中对象都需要考虑线程安全的问题,同时有垃圾回收机制。

堆溢出问题解决:

通常会出现java.lang.OutofMemoryError:java heap space的错误信息。

首先通过jps查看到当前有哪些java进程在运行。

接着采用jmap查看堆使用情况,通常jmap只能查看某一时刻的信息。jmap -heap 进程id

jconsole工具可以以图形化界面看到相关的监控信息,做到连续监控。连接jconsole,打开其图形化界面,进行查看。

采用jvisualvm ,可以进行堆dump日志分析,排查问题。

5.方法区:Method Area

主要存放成员方法、方法、构造方法、运行时常量池(String Table)

虚拟机启动时被创建,逻辑上是堆的一部分。jdk1.7及以前,存放在永久代中。而jdk1.8的时候存放在metaspace中。

方法区jdk1.7的时候会出现溢出,但jdk1.8之后存放在metaspace元空间中,因此通常情况下不会出现内存溢出的情况。

方法区常量池:运行时常量池StringTable

常量池就是一张类似于hash一样的表。虚拟机指令根据这张表找到执行的类名、方法名、类、字面量等信息。当类文件被加载时常量信息会加载到运行时常量池中,并把里面的符号地址变成真实地址。

串池(调用intern方法就可以放入)中如果有的常量,则不会到常量池中去找,其加载策略是惰性的。常量池中的字符串是符号,第一次用到时才是对象。同时利用串池可以避免重复创建,节省内存。字符串拼接通常是在编译期优化的。

如果项目中常量信息较多,同时又有重复,则可以考虑串池进行调优。同时如果常量信息较多,也可以调大桶的个数,由于其本身就是一张表。-XX:stringTableSize=桶个数

6.直接内存:Direct Memory

操作系统内存,常用于NIO操作时,用于数据缓冲区,分配回收成本较高,但读写性能高,不受jvm内存回收管理。

分配与回收:使用unsafe对象完成直接内存的分配和回收,分配内存可以采用allocateMemory来进行分配内存,并且回收需要主动调用freeMemory方法。ByteBuffer的实现类内部使用了cleaner虚引用来监测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就会由ReferenceHandler线程通过clear的clean方法调用freeMemory来释放内存。

相关引用

强引用、软引用、弱引用、虚引用、终结器引用

强引用:只有所有GC roots对象都不通过强引用引用该对象,该对象才能被垃圾回收。

软引用:仅有软引用该对象,在垃圾回收后,内存还不足时会再次触发垃圾回收,回收软引用对象,可以配合引用队列来释放引用自身。

弱引用:仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象,可以配合引用队列来释放引用自身。

虚引用:必须配合引用队列使用,主要配合ByteBuffer使用,被引用对象回收时,会被徐引用入队,由Referencehandler线程调用虚引用相应的方法来释放直接内存。

终结器引用:无需手动编码,但器内部配合引用队列使用,在垃圾回收时,终结器引用入队,找到被引用对象并调用finalize方法,第二次GC回收的时候才能回收被引用对象。

垃圾回收

如何判断对象可以回收?采用可达性分析算法,也即没有引用的对象,通常会进行回收,也即孤立的对象会被回收。

垃圾回收算法:

通常可分为三种:标记清除mark sweep、标记整理mark compact、复制copy。

这三种算法:标记清除算法速度快,但产生内存碎片较多,不利于内存的充分使用。标记整理,速度适中,同时能够整理内存碎片。复制算法,速度最慢,但不会产生内存碎片,占用内存双倍。

由于三种算法都有其优点和缺点,因此需要综合使用它们。因此就产生了分带垃圾回收算法。

新生代由于产生的对象是朝生夕死的,因此通常会常用复制算法,而老年代则采用标记整理或标记清除算法。

同时可分为新生代、老年代、MetaSpace区(jdk1.7永久代)

新生代又可分为Eden区、Survivor区,而Survivor区又可分为From、To两部分。

对象存活区域:

1.通常首先分配在Eden区

2.新生代空间不足时,会触发minor gc,Eden区和from存活对象使用copy算法复制到to中,存活的对象年龄+1,并且交换from、to

3.minor gc会引发stop the world,暂停其他用户的线程,等垃圾回收结束,用户线程才回复运行

4.当对象寿命超过阀值时,会晋升到老年代,最大寿命是15(4bit)

5.当老年代空间不足时,会先尝试触发minor gc,如果空间不足,那么触发full gc,stw的时间更长


相关jvm参数:

堆初始化大小:-Xms

堆最大大小:-Xmx或-XX:MaxHeapSize=size

新生代大小:-Xmn或-XX:newSize=size+-XX:MaxNewSize=size

幸存区比例(动态):-XX:InittalSurvivorRatio=ratio和-XX:+UseAdaptiveSizePolicy

幸存区比例:-XX:SurvivorRatio=ratio

晋升阀值:-XX:MaxTenuringThreshold=threshold

晋升详情:-XX:+PrintTenuringDistribution

GC详情:-XX:+PrintGCDetails -verbose:gc

FullGC前MinorGC:-XX:+scavengeBeforeFullGC

垃圾回收器:

可以分为串行垃圾回收器、并行垃圾回收器、并发垃圾回收器、G1等

串行垃圾回收器:单线程、堆内存较小,适合个人电脑,-XX:+userSerialGC=Serial+SerialOld,串行新生代和老年代

并行垃圾回收器:多线程,吞吐量高,-XX:+UserParallelGC —— -XX:+UseParallelOldGC,-XX:GCTimeRatio=ratio,-XX:MaxGCPauseMillis=ms,-XX:ParallelgcThreads=n,并行GC,新生代和老年代,同时可以设置比例,响应时间、线程数等信息

并发垃圾回收器:多线程,响应时间短,-XX:+UseConcMarkSweepGC—— -XX:UseParNewGC——SerialOld,-XX:ParallelGCThreads=n—— -XX:Concgcthreads,-XX:CMSInitiatingOccupancyFranction=percent,-XX:+CMSScavengeBeforeRemark,包含信息并发新生代GC,串行Old,并发线程数,CMS比例,重新标记再清理

G1垃圾回收器:

使用场景:注重高吞吐量,低延迟的场景,默认的暂停目标是200ms。超大堆内存,会将堆划分为多个大小相等的Region,整体上标记+整理算法,两个区域之间采用复制算法。

相关参数:

-XX:+UseG1GC

-XX:G1HeapRegionsSize=size

-XX:MaxGCPauseMillis=time

垃圾回收阶段:

Young Collection、Mixed Collection、Young Collection+Concurrent Mark

Young Collection:会STW.

Young Collection+CM:在Young GC时会进行GC Root的初始化标记,老年代占用堆空间比例达到阀值时,进行并发标记,不会STW.

Mixed Collection:会对E、S、O进行全面垃圾回收,最终标记会STW,拷贝存活会STW

进行Full GC:相关代的FullGC

Young Collection跨代引用:新生代回收的跨代引用(老年大引用新生代)问题:卡表与Remebered Set,在引用变量时通过post-write barier+dirty card queue进行处理,同时concurrent refinement threads更新Remembered Set.

Remark:pre-write barrier + satb_mark_queue

通常调优需要考虑:内存、锁竞争、cpu占用、IO、代码这些层面上的调优。

通常最快的GC:

考虑不发生GC,也即查看FullGC前后的内存占用,考虑数据是否太多、数据表示是否太大、是否存在内存泄漏(变量的作用范围、是否存在软、弱引用、第三方缓存等)。

目录
相关文章
|
6月前
|
Oracle Java 编译器
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)
基本概念【入门、 发展简史、核心优势、各版本的含义、特性和优势、JVM、JRE 和 JDK 】(二)-全面详解(学习总结---从入门到深化)
87 1
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
68 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
33 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
1月前
|
Java 应用服务中间件 程序员
JVM知识体系学习八:OOM的案例(承接上篇博文,可以作为面试中的案例)
这篇文章通过多个案例深入探讨了Java虚拟机(JVM)中的内存溢出问题,涵盖了堆内存、方法区、直接内存和栈内存溢出的原因、诊断方法和解决方案,并讨论了不同JDK版本垃圾回收器的变化。
30 4
|
1月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
46 3
|
1月前
|
SQL 缓存 Java
JVM知识体系学习三:class文件初始化过程、硬件层数据一致性(硬件层)、缓存行、指令乱序执行问题、如何保证不乱序(volatile等)
这篇文章详细介绍了JVM中类文件的初始化过程、硬件层面的数据一致性问题、缓存行和伪共享、指令乱序执行问题,以及如何通过`volatile`关键字和`synchronized`关键字来保证数据的有序性和可见性。
30 3
|
1月前
|
缓存 前端开发 Java
JVM知识体系学习二:ClassLoader 类加载器、类加载器层次、类过载过程之双亲委派机制、类加载范围、自定义类加载器、编译器、懒加载模式、打破双亲委派机制
这篇文章详细介绍了JVM中ClassLoader的工作原理,包括类加载器的层次结构、双亲委派机制、类加载过程、自定义类加载器的实现,以及如何打破双亲委派机制来实现热部署等功能。
48 3
|
1月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
56 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
1月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
45 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
5月前
|
缓存 Java
《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)
《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)
50 0