JVM堆与堆调优以及出现OOM如何排查

news/2024/11/7 15:35:23/

调优的位置——堆

Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。
类加载器读取了类文件后,一般会把什么东西放到堆中?类,方法,常量,变量~,保存我们所有引用类型的真实对象;
堆内存中还要细分为三个区域:
1.新生区(0区/1区):类诞生和成长的地方,甚至死亡。其中的伊甸园区,是所有的new对象发生的地方。
2.养老区:从新生区经过GC之后存活下来的对象进入养老区
3.永久区:这个区域常驻内存的。用来存放DK自身携带的Class对象。Interface元数据,存储的是Java运行时的一些环境或类信息,这个区域不存在垃圾回收!关闭VM虚拟就会释放这个区域的内存

在堆中主要存放加载的Class类级对象如class本身,method,field等等
在这里插入图片描述
幸存区0和1在堆内存中是一个动态变化的情况他是伊甸园区和养老区之间的一个过渡,顾名思义无法幸存的对象会被“kill”,GC垃圾回收主要在新生区中的伊甸园区和养老区进行。回收的方式分为轻GC与重GC,其中轻GC主要存在于新生区,只有当进入老年区的垃圾对象超过限额才会触发重GC(full GC),该操作主要存在于养老区。
在这里插入图片描述
在开发中可能遇到OOM的问题,表示内存不够,这个内存也就是JVM的堆内存,比如下面这个例子:
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
在这里插入图片描述
99%的对象都是临时对象,所以经过GC之后很少有进入到老年区中,因此OOM的情况也很少发生

永久区的演变

这个区域常驻内存的。用来存放IDK自身携带的Class对象。Interface元数据,存储的是Java运行时的一些环境或类信息。

jdk1.6之前︰永久代,常量池是在方法区;
jdk1.7︰永久代,但是慢慢的退化了,去永久代,常量池在堆中
jdk1.8之后:无永久代,常量池在元空间

在这里插入图片描述

OOM的出现

永久区内存崩溃的情况:一个启动类,加载了大量的第三方jar包。Tomcat部署了太多的应用,大量动态生成的反射类。不断的被加载。直到内存满,就会出现OOM;
在这里插入图片描述
默认情况下:分配的总内存是电脑内存的四分之一,初始化的内存是电脑内存的六十四分之一
但是这些内存参数是可以人为调整的
在这里插入图片描述
运行程序后,发现JVM参数发生了变化
在这里插入图片描述

可以看出,元空间逻辑上存在,但物理上并不存在

出现OOM如何去排查

可以使用内存快照工具分析对象,主要有:MAT(Eclipse),Jprofile(IDEA)两种工具。
向VM传入以下参数即可
在这里插入图片描述
当程序运行出现OOM,进入类所在的文件目录下去寻找Jprofile生成的hprof文件即可。
在这里插入图片描述

双击打开即可初步发现占用大量内存的对象,俗称“大对象”
在这里插入图片描述

查看线程(Thread Dump)即可发现程序中出现问题的所在行。
在这里插入图片描述
针对具体情况就可以进行JVM相关调优参数进行调优:
在这里插入图片描述
分享一些其他的JVM参数:
-Xmx4g:堆内存最大值为4GB。
-Xms4g:初始化堆内存大小为4GB。
-Xmn1200m:设置年轻代大小为1200MB。增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss512k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1MB,以前每个线程堆栈大小为256K。应根据应用线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=8:设置年轻代中Eden区与Survivor区的大小比值。设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:PermSize=100m:初始化永久代大小为100MB
-XX:MaxPermSize=256m:设置持久代大小为256MB
-XX:MaxTenuringThreshold=15:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过
可调优参数:
-Xms:初始化堆内存大小,默认为物理内存的1/64(小于1GB)
-Xmx:**堆内存最大值。**默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。
-Xmn:新生代大小,包括Eden区与2个Survivor区
-XX:SurvivorRatio=1:Eden区与一个Survivor区比值为1:1
-XX:MaxDirectMemorySize=1G:**直接内存。**报java.lang.OutOfMemoryError: Direct buffer memory异常可以上调这个值。
-XX:+DisableExplicitGC:禁止运行期显式地调用System.gc()来触发fulll GC
注意: Java RMI的定时GC触发机制可通过配置-Dsun.rmi.dgc.server.gcInterval=86400来控制触发的时间。
-XX:CMSInitiatingOccupancyFraction=60:老年代内存回收阈值,默认值为68
-XX:ConcGCThreads=4:CMS垃圾回收器并行线程线,推荐值为CPU核心数
-XX:ParallelGCThreads=8:新生代并行收集器的线程数
-XX:MaxTenuringThreshold=10:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。
-XX:CMSFullGCsBeforeCompaction=4:指定进行多少次fullGC之后,进行tenured区 内存空间压缩

-XX:CMSMaxAbortablePrecleanTime=500:当abortable-preclean预清理阶段执行达到这个时间时就会结束


http://www.ppmy.cn/news/31239.html

相关文章

第十四届蓝桥杯三月真题刷题训练——第 6 天

目录 第 1 题:星期计算 问题描述 运行限制 代码: 第 2 题:考勤刷卡 问题描述 输入格式 输出格式 样例输入 样例输出 评测用例规模与约定 运行限制 代码: 第 3 题:卡片 问题描述 输入格式 输出格式 样…

ubuntu 使用 CMake 构建 Qt5 项目

Qt 概述 概念 Qt 是一个跨平台的 C 图形用户界面应用程序框架 常见的 C GUI: Qt 和 MFC 跨平台 Windows Linux MacOS 嵌入式平台 版本 包括商业版和开源免费版 案例 Linux 桌面环境 KDE WPS Office Qt 安装 下载地址: https://download.qt.io/archive/qt/ http…

linux下进不去adb

linux 进不去adb cat /sys/kernel/debug/usb/devices 查看是否有adb口 首先查看adb是否被识别成串口 option 如果被识别成串口 方法1: https://patchwork.kernel.org/project/linux-usb/patch/20180723140220.7166-1-romain.izard.progmail.com/ diff --git a/dri…

Qt使用API实现鼠标点击操作

前段时间,工作需要进行数据录入,每次都要点击3次按钮,想让鼠标自行点击,只要下位机接入,就自动点击按钮把数据读出,录入到服务端,并且进行检测,说干就干,没有经验,那只有面向百度编程. 根据查到的资料,可以使用WinAPI进行鼠标模似.可以使用的函数有两个,一个是SendMessageA(),…

Python每日一练(20230309)

目录 1. 删除有序数组中的重复项 ★ 2. 二叉树的最小深度 ★★ 3. 只出现一次的数字 II ★★ 🌟 每日一练刷题专栏 C/C 每日一练 ​专栏 Python 每日一练 专栏 1. 删除有序数组中的重复项 给你一个有序数组 nums ,请你原地删除重复出现的元素…

【冲刺蓝桥杯的最后30天】day6

大家好😃,我是想要慢慢变得优秀的向阳🌞同学👨‍💻,断更了整整一年,又开始恢复CSDN更新,从今天开始更新备战蓝桥30天系列,一共30天,如果对你有帮助或者正在备…

Linux-0.11 kernel目录进程管理sched.c详解

Linux-0.11 kernel目录进程管理sched.c详解 sched.c主要功能是负责进程的调度,其最核心的函数就是schedule。除schedule以外, sleep_on和wake_up也是相对重要的函数。 schedule void schedule(void)schedule函数的基本功能可以分为两大块,…

回文日期(蓝桥杯真题)小白入!

//明白打表的重要性,哭了 #include<iostream>using namespace std;int date[15]{0,31,29,31,30,31,30,31,31,30,31,30,31}; //为什么要从0&#xff0c;开始&#xff0c;由于我们想使用i(月份)作为所以&#xff0c;月份是从1开始的 //还有一点&#xff0c;不能怪我们&…