JVM相关知识

JVM主要有堆、方法区、虚拟机栈、本地方法栈、程序计数器组成

线程私有区域:

程序计数器:字节码执行的都有一个编号,就是程序计数器,解释器按这个计数器执行字码,将字节码转换为机器码给cpu运行。其二就是多线程中,也是时间片用完(会用程序计数器记录当前执行到的位置),因为有程序计数器,所以下次再获取时间片时,就可以继续接下去的操作

虚拟机栈:为虚拟机执行Java方法服务。

本地方法栈: 为虚拟机使用到的Native方法服务(本地方法一般就是Native关键字修饰,库里本来就有的方法,有的实现类是用c++实现的,直接调用方法使用就行.总结:java调用非java代码的接口)

线程共有区域(线程共享):

堆:通过new关键字创建的对象都会使用堆内存(它是线程共享的,堆中的对象都要考虑线程安全问题,有垃圾回收机制)

方法区:类信息,类加载器、运行时常量池(当虚拟机要使用一个类时,它需要读取并解析 Class 文件获取相关信息,再将信息存入到方法区。方法区会存储已被虚拟机加载的 类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据。)(以前有永久代、现在有元空间)

操作系统内存

直接内存(常见于NIO操作,用于数据缓冲区。分配回收成本较高,但读写性能高。不受JVM内存回收管理)

一、线程运行诊断

案例一:cpu占用过多

定位

(1)用top命令,定位哪个进程cpu的占用过高

(2)ps H -eo pid,tid,%cpu | grep 进程id(进一步定位那个线程引起的cpu占用过高)

(3)jstack 进程id (将线程转换为16进制,jstack命令得到结果的 nid,找到占用cpu的线程),进一步定位到问题代码的源码行数

案例二:程序运行很长时间没有结果

可能发生死锁

(1)使用jstack 进程id 查看

(2)看到有(Found one Java-level deadlock),定位到相应的源码行数

二、堆内存溢出(OutOfMemoryError:Java heap space)

显示指定堆内存(设置堆内存大小和最大堆内存大小)

-Xms<heap size>[unit] 初始化堆内存大小

-Xmx<heap size>[unit] 最大堆内存大小

例如-Xms2G 、-Xmx8G

堆内存诊断

1、jps工具

查看当前系统中有哪些java进程

2、jmap工具

查看堆内存占用情况

3、jconsole工具

图形界面的、多功能的监测工具,可以连续检测

4、jvisualvm工具

也是图形化界面

jmap heap 进程ip(查看进程的堆内存信息,占用情况)

jconsole(命令行执行,就会弹出一个图形化界面,里面会有相应的监控信息)

案例 垃圾回收后,内存占用任然很高

使用jconsole执行垃圾回收(发现堆内存还是很高)

jvisualvm(弹出可视化界面)

这样就能查找到占用内存高的对象

三、元空间内存溢出OutOfMemoryError:Metaspace(1.8以前是叫永久代,1.8以后叫元空间,是方法区内的,类信息占用内存大于最大值会溢出)

永久代:

-XX:MaxPermSize=8m

元空间:

-XX:MaxMetaspaceSize=8m

三、String Table垃圾回收(intern()方法能进常量池)

-Xmx10m -XX:+PrintStringTableStatics -XX:+PrintGCDetails -verbose:gc(显示垃圾回收的信息)

StringTable 性能调优:

1、调整-XX:StringTableSize=桶个数

-Xms500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=1009(如果读取字符串常量比较多, -XX:StringTableSize=1009把这个池调大,减少哈希冲突,使得性能提升)

2、考虑将字符串对象是否入池

四、直接内存释放原理

1、使用unsafe.allocateMemory() 释放直接内存

2、ByteBuffer的实现类内部,使用Cleaner(虚引用)来监测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,那么就会由ReferenceHandler线程通过Cleaner的clean方法调用freeMemory来释放直接内存

-XX:+DisableExplicicitGC 显示回收垃圾无效

System.gc() 执行这个是执行一次Full GC,使用上面那个参数,会无效

五、判断垃圾

1、引用计数法:每被引用一次,就计数+1,引用0就可回收

2、可达性分析:(根对象是那种不能被当成垃圾回收的对象,看对象有没有被根对象直接或间接引用,若有就不能当成垃圾回收,否则就可以被垃圾回收)

下载Memory Analyzer(MAT)工具

步骤,控制台输入:

jps 获得进程id

jmap -dump:format=b,live,file=要存储的文件名.bin 进程id

将bin文件在Mat工具中打开

即可查看哪些对象是根对象

JAVA中的四种引用

1、强引用(A1对象)

只要沿着GC Root被引用,那就是强引用不会被回收

2、弱引用(通过SoftReference),如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。

(代码示例如下)

-Xmx20m -XX:+PrintGCDetails -verbose:gc 打印查看垃圾回收过程

3、弱引用的特点是不管内存是否足够,只要发生 GC,都会被回收。

4、虚引用

必须配合引用队列使用,主要配合ByteBuffer使用,被引用对象回收时,会将虚引用入队,由Reference Handler线程调用虚引用相关方法(Unafe.freeMemory)释放直接内存

5、终结器引用

无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用它的finalize方法,第二次GC才能回收被引用对象

六、垃圾回收算法

1、标记清除(缺点:会产生垃圾碎片)

2、标记整理

3、复制算法(缺点,内存只能有一半被使用)

七、 垃圾回收器

1、串行垃圾回收器(只有一个线程进行GC)

-XX:+UseSerialGC=Serial + SerialOld (新生代用复制算法,老年代用标记-整理算法)

2、吞吐量优先

并行垃圾回收器(多个线程一起进行垃圾回收)

-XX:+UseParallelGC -XX:+UseParallelOldGC (只要开启其中一个,就会开启另一个)

参数:自适应调整新生代大小、调整垃圾回收时间与总时间比例、最大暂停毫秒数、线程数

3、响应时间优先

-XX:+UseConcMarkSweepGC (用户工作线程与垃圾线程一起并行,工作在老年代的垃圾回收器)

与-XX:+UseParNewGC~SerialOld 一起使用的(当垃圾回收器出现问题,它就会退化为SerialOld)

参数

4、G1垃圾回收器(JDK9被设为默认回收器)

适用场景

同时注重吞吐量和低延迟,默认暂停目标是200ms

超大堆内存,会将堆划分为多个大小相等的Region

整体上是标记+整理算法,两个区域之间是复制算法

-XX:+UseG1GC

垃圾回收过程

复制到幸存区

去重

七、GC调优

去 官网查看

或者用命令行查看

(1)调优领域

1、内存

2、锁竞争

3、cpu占用

4、io

(2)确定目标

1、低延迟还是高吞吐量,选择合适的回收器

2、CMS、G1、ZGC

3、ParallelGC

(3)最快的GC是不发生GC

1、查看FullGC前后的内存占用,考虑下面几个问题

数据是不是太多

数据表示是否太臃肿

是否存在内存泄漏

八、新生代调优

新生代

内存不是占越大越好,差不多25%-50%之间

幸存区

1、幸存区要大到能保留(当前活跃对象+需要晋升的对象)

2、(因为幸存区是复制算法,需要复制来复制去)

老年代调优

案例

案例1 Full GC 和 Minor GC频繁

新生代内存不足, 当业务高峰期来临,大量对象被创建,幸存区不够,大量对象被放到老年区,导致老年区也满了触发FullGC。

所以增大新生代内存,幸存区内存调大,阈值调高。

案例2 请求高峰期发送FullGC,单次暂停时间特别长(CMS)

重新标记前先对垃圾进行清理

案例3 老年代充裕情况下,发生Full GC(CMS jdk1.7)

1.7及以前 永久代空间不足也会导致Full GC

1.8 元空间不足也会导致Full GC

相关推荐
天“码”行空25 分钟前
java面向对象的三大特性之一多态
java·开发语言·jvm
独自破碎E6 小时前
JVM的内存区域是怎么划分的?
jvm
期待のcode7 小时前
认识Java虚拟机
java·开发语言·jvm
leaves falling10 小时前
一篇文章深入理解指针
jvm
linweidong11 小时前
C++ 中避免悬挂引用的企业策略有哪些?
java·jvm·c++
曹轲恒11 小时前
JVM中的直接内存
jvm
BHXDML12 小时前
JVM 深度理解 —— 程序的底层运行逻辑
java·开发语言·jvm
隐退山林13 小时前
JavaEE:多线程初阶(二)
java·开发语言·jvm
期待のcode14 小时前
Java虚拟机堆
java·开发语言·jvm
alonewolf_991 天前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk