JVM调优详解

news2024/9/21 4:27:32
    @SneakyThrows
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        ArrayList arrayList = new ArrayList();
        Byte[] e = new Byte[1024];
        while (true) {
            Thread.sleep(10);
            arrayList.add(e);
        }
    }

 java执行代码

C:\WINDOWS\System32>jps -l
26576 org/netbeans/Main
5156 org.netbeans.lib.profiler.server.ProfilerServer
19272 sun.tools.jps.Jps
26312
8232 com.jesse.log.JVMTest
24204 org.jetbrains.jps.cmdline.Launcher

jps -l 显示java pid

C:\WINDOWS\System32>jmap -dump:live,format=b,file=d:/a.dump 8232
Dumping heap to D:\a.dump ...
File exists

使用jmap导出dump

-dump:live 会执行一次fullgc, 导出存活的对象

format=b 二进制格式, 不填默认也是二进制格式

file=d:/1.dump 导出文件的路径

8232 pid

说白了, 调优主要看fullGC垃圾回收的频率, 和垃圾回收的时间.和回收的垃圾多少

如果垃圾回收频率高, 回收时间短. 那要看回收的垃圾多不多, 一般这种情况很少, 有没有可能把老年代的空间设置太小了. 正常老年代的空间都是比较大的, 即使回收的垃圾少, 他的执行时间也不会短的. 

如果垃圾回收时间长, 那就要调优了. 即使频率低, 执行时间长也是要调优的, 对于并发执行的垃圾回收器, 主要要STW执行的时间长短. 如何执行长, 会直接影响到客户端体验. 可能原因是不是设置老年代的堆内存多大, 如果4-8G, 最好是用G1垃圾回收器. 如果回收频率很高, 回收的内存也很多, 及要看一下对象是不是过早晋升到老年代了. 除了看代码, 还要看新生代的内存是不是设置的太小了. 如果回收的内存不多, 就要看下老年代是不是设置的太小, 还是代码有问题. 本身没有用的对象却常驻内存. 

-Xms 512M  jvm初始化内存

-Xmx 512M jvm最大内存

-Xmn512M 新生代的内存

-Xss512K 栈的大小

-XX:+UseConcMarkSweepGC  使用CMS

-XX:+PrintGCDetails 打印GC详情

-XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps 打印GC的时间

-XX:+PrintGCHeapAtGC 打印GC的堆信息

-Xloggc:d:/a.log  指定GC日志路径

-Xms512M
-Xmx512M
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-XX:+PrintHeapAtGC
-Xloggc:d:/a.log

运行参数

Connected to the target VM, address: '127.0.0.1:12967', transport: 'socket'
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.jesse.log.JVMTest.main(JVMTest.java:19)
Disconnected from the target VM, address: '127.0.0.1:12967', transport: 'socket'

Process finished with exit code 1

 java.lang.OutOfMemoryError: Java heap space  java堆空间, java内存溢出

Java HotSpot(TM) 64-Bit Server VM (25.101-b13) for windows-amd64 JRE (1.8.0_101-b13), built on Jun 22 2016 01:21:29 by "java_re" with MS VC++ 10.0 (VS2010)
Memory: 4k page, physical 12446092k(5781004k free), swap 21079212k(10336556k free)
CommandLine flags: -XX:InitialHeapSize=536870912 -XX:MaxHeapSize=536870912 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 153088K, used 129019K [0x00000000f5580000, 0x0000000100000000, 0x0000000100000000)
  eden space 131584K, 98% used [0x00000000f5580000,0x00000000fd37ee30,0x00000000fd600000)
  from space 21504K, 0% used [0x00000000feb00000,0x00000000feb00000,0x0000000100000000)
  to   space 21504K, 0% used [0x00000000fd600000,0x00000000fd600000,0x00000000feb00000)
 ParOldGen       total 349696K, used 0K [0x00000000e0000000, 0x00000000f5580000, 0x00000000f5580000)
  object space 349696K, 0% used [0x00000000e0000000,0x00000000e0000000,0x00000000f5580000)
 Metaspace       used 7257K, capacity 7292K, committed 7552K, reserved 1056768K
  class space    used 849K, capacity 856K, committed 896K, reserved 1048576K
2023-07-27T14:53:32.453+0800: 8.662: [GC (Allocation Failure) [PSYoungGen: 129019K->21480K(153088K)] 129019K->112507K(502784K), 0.0292881 secs] [Times: user=0.13 sys=0.02, real=0.03 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 153088K, used 21480K [0x00000000f5580000, 0x0000000100000000, 0x0000000100000000)
  eden space 131584K, 0% used [0x00000000f5580000,0x00000000f5580000,0x00000000fd600000)
  from space 21504K, 99% used [0x00000000fd600000,0x00000000feafa070,0x00000000feb00000)
  to   space 21504K, 0% used [0x00000000feb00000,0x00000000feb00000,0x0000000100000000)
 ParOldGen       total 349696K, used 91027K [0x00000000e0000000, 0x00000000f5580000, 0x00000000f5580000)
  object space 349696K, 26% used [0x00000000e0000000,0x00000000e58e4ef8,0x00000000f5580000)
 Metaspace       used 7257K, capacity 7292K, committed 7552K, reserved 1056768K
  class space    used 849K, capacity 856K, committed 896K, reserved 1048576K
}

查看a.log日志信息

Java HotSpot(TM) 64-Bit Server VM (25.101-b13) for windows-amd64 JRE (1.8.0_101-b13), built on Jun 22 2016 01:21:29 by "java_re" with MS VC++ 10.0 (VS2010) = JVM版本, java版本

Memory: 4k page, physical 12446092k(5781004k free), swap 21079212k(10336556k free)

= 一页4k, 物理内存约12G, 约6G空闲, swap约21G, 约10G空闲

 PSYoungGen      total 153088K, used 129019K = 年轻代150M使用130M

eden space 131584K, 98% used  =  eden空间130M, 已使用98%

from space 21504K, 0% used = from空间21M, 已使用0%

to   space 21504K, 0% used = to空间21M, 已使用0%

ParOldGen       total 349696K, used 0K = 老年代350M, 使用...

object space 349696K, 0% used = 对象空间350M 已使用0%

Metaspace       used 7257K, = 元空间 已使用7M

class space    used 849K = class空间 已使用849k

太麻烦了, 可以使用工具gceasy

文件名称和GC总共花费的时间

新生代 150M , 老年代350M, 元空间 1G, 公共1.5G

 Allocated 分配的内存

Peak  最高峰的内存数值

 吐出量94%, 延长 GC平均时间148ms, 最大的GC时间410ms

每个时间间隔GC个数的比例

1-100ms 占36%

100-200ms 占36%

 GC Duration 可以看YGC和FullGC的次数和持续时间 

Heap after GC GC之后的堆内存

Heap before GC GC之前的堆内存

Reclaimed bytes GC回收的字节大小

Young GC  YGC回收内存前后的内存变化

old GC fullGC回收奴才能前后的内存变化

Meta Space 元空间回收内存的情况

 Reclaimed Bytes YGC和FullGC是否内存的多少

GC cumulative time YGC累计时间和FullGC累计时间的比例

GC Average Time YGC和FullGC平均时间

Full GC Count 总的GC次数

Full GC reclaimed GC释放内存的大小

Full GC total time FullGC总共花的时间

Full GC avg time FullGC平均时间

Full GC avg time std dev FullGC平均时间标准偏差

Full GC min/max time FullGC花费最小和最大的时间

Full GC Interval avg FullGC的平均时间间隔

报告分享

G1的配置参数说明

-XX:+UseG1GC  使用G1垃圾收集器

-XX:+G1HeapRegionSize=32M  Region的大小

-XX:+G1NewsizePercent=20  新生代初始化占用20%比例的内存

-XX:+G1MaxNewsizePercent=50  新生代最大占用50%的堆内存

-XX:+G1OldcsetRegionThresholdPercent=10  老年代初始化10内存

-XX:+ParallelPCThread=8  并发收集线程, 最多8个

-XX:+ConcthreadCount=2 并发标记线程数, 一般设置为ParallelPCThread的1/4

-XX:+InitiatingOccupancyPencent=45 内存超过45%就会执行fullGC. 不配置默认是45%

-XX:+MaxGCPauseMillis 最大的GC停顿时间

-XX:+HeapDumpOnoutofMemoryError  内存溢出导出堆文件

-XX:HeapDumpPath=d:/g1.hprof  堆文件快照导出文件路径

-XX:+PrintGC 打印GC信息

-XX:+PrintGCDetails  打印GC详情

-XX:+PrintGCTimeStamps 打印GC时间

-XX:+PrintGCDateStamps 打印GC时间

-Xloggc=d:/g1.log  打印GC文件路径

-XX:+UseTLAB 使用功能TLAB, 叫做指针碰撞, 就是线程会向主内存申请一定大小的内存. 通过CAS的方式获取

-XX:+PrintTLAB  打印TLAB

-XX:+TLABSize TLAB的大小

-XX:+DisableExplicitGC 禁用System.gc()

CMS配置参数说明

-XX:+ConcMarkSweepGC  老年代使用CMS

-XX:+ParallelGCThreads 并发收集线程数

-XX:+CMSInitiatingOccupancyFraction=68  达到多少执行CMS, 默认是达到68%

-XX:+UseCMSCompactAtFullCollection  在fullGC的时候进行压缩

-XX:+CMSFullGCCsBeforeCompaction  在fullGC多少次之后压缩

-XX:+CMSClassUnloadingEnabled  垃圾回收的时候, 启动类卸载, 默认是开启的

-XX:+CMSInitiatingPermOccupancyFraction 达到多少回收Perm, java中不推荐

-XX:+GCTimeRatio 设置GC占用户运行时间比, 不推荐

-XX:+MaxGCPauseMillis  最大GC暂停时间, 是一个建议的时间

  

-Xms512M
-Xmx512M
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-XX:+PrintHeapAtGC
-Xloggc:d:/a.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=d:/ps.hprof

内存溢出导出堆文件

D:\>jhat ps.hprof
Reading from ps.hprof...
Dump file created Thu Jul 27 16:39:34 CST 2023
Snapshot read, resolving...
Resolving 38143 objects...
Chasing references, expect 7 dots.......
Eliminating duplicate references.......
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

jhat ps.hprof 之后, 通过localhost:7000访问

不好用, 放弃...

使用VisualVM 打开ps.hprof

 char, String 两个占用比较高

G1可以设定暂停时间, 默认是200ms.收集过程分为初始标记, 并发标记, 重新标记, 清除. 除了并发标记可以和用户线程一起运行之外, 其他都需要STW. 

并发标记的又可能出现的情况是

一 是垃圾的但是没有标记, 这种问题不大, 大不了下次垃圾回收的时候回收掉. 

二 不是垃圾, 但是标记为垃圾. 这个问题就很大. 出现这个情况的可能原因是某个rootA对象引用A对象, 另外一个用户线程B拿到对象A的地址. 用户线程A让rootA对象不引用对象A. 此时垃圾回收线程扫描rootA, 发现没有引用A对象, 扫描rootB没有引用A对象, 这是垃圾回收线程标记A对象不可达, 为垃圾, 然后用户线程B让rootB引用A对象. A不应该是垃圾, 却被回收了, 这是不可以的. 

如果解决这个问题呢? 我们看到rootA删除了A对象, rootB添加了A对象, 才会导致这样的问题. 

我们发现

只删除A对象, 不添加A对象, 就不会出现这个的问题. 

G1使用的三色标记法

黑色  回收器已经访问该节点, 并访问的这个节点指向的所有节点

灰色  回收器已经访问这个节点, 他指向的节点还有访问完

白色 回收器还没有访问的节点

用户线程1删除黑色  没有问题, 垃圾回收器这次没有回收, 下次回收会判断它是不是垃圾

用户线程1删除灰色  也没有问题, 因为垃圾回收线程已经获取灰色节点的指针, 可以继续访问下去. 也会在下次回收判断是不是垃圾

用户线程1删除白色A  有问题, 因为白色A垃圾回收器没有访问过, 当它遍历完之后, 发现白色不可达, 会判断A是垃圾, 会被回收. 如果存在这种情况, 在用户线程1删除白色A的时候, 用户线程B已经获取白色A的地址, 在垃圾回收器标记A为垃圾的时候, 之后用户线程B把对象A赋值给某个变量. 然后垃圾回收器回收了A对象, 用户线程B使用对象A就会出现空指针的情况. 

那么如何处理这种情况. 

我们发现, 不允许删除白色节点, 不靠谱. 那就在新增节点下手. 

用户线程2对白色节点新增节点A  没有问题, 垃圾回收器会遍历这个节点, 即使之前用户线程1删除节点A. 

用户线程2对灰色节点新增节点A  也没有问题, 只要新增之后垃圾回收器扫描这个节点就可以了

用户线程2对黑色节点新增节点A  有问题, 因为黑色节点表明垃圾回收器已经扫描完了. 不会在标记A, 如果之前标记了A是垃圾的话, 就会有问题. 

所以我针对第三种情况, 如果用户线程在黑色节点添加一个节点, 那么就会把这个黑色的节点变成灰色, 把这个灰色的节点记录下来, 在接下来的重新标记, 重新标记是STW的. 会从这个灰色的节点扫描下去. 

CMS是从新增节点入手, 叫做增量更新

G1是总删除节点入手, 叫做原始快照, 解决办法是删除的这个节点这个垃圾回收不回收这个节点, 等下次垃圾回收判断它是否是垃圾. 只有用户线程删除灰色到白色这样的节点才不回收. 

java1.6, java1.7, java1.8默认是使用PS, PO垃圾收集器

一般用parallelNew+CMS

java1.9默认是使用G1垃圾回收器

垃圾回收算法有标记清除, 标记复制, 标记整理. 

G1设置有Region的概念, 可以设置大小, Region可以eden1区, servious区, old区, 还有大对象区. YGC的时候会把eden和s1的存活对象复制到s2, fullGC的时候会把eden和s1的存活的对象复制s2, 还有标记整理老年代的对象. 

新增对象会存在这几种情况

新增对象的时候, 被老年代引用.那这样的对象在YGC的时候是不可以回收的. 为了判断它是不是垃圾, 重新扫描一遍Old区是不可以行的. 所以需要一个记录表, 叫记忆集. 主要记录老年代对新生代的引用,  和这个新生代做好映射关系. 主要是回收这个新生代的内存的时候, 查这个记录表. 因为G1有多个Region, 所以会记录这个对象被哪些Region引用. 如果以对象映射记录的话, 如果对象很小,  如果存在大量的对象, 那就要不少的数据空间存放. 所以想到了把内存划分成多个区域, 一个区域的空间是16k, 如果这个区域的对象被其他地方的对象引用, 就会变为1. 垃圾回收的时候就会回收这个区域. 这样的方法叫卡表. 那当这个区域的对象不用的时候, 什么时候变回0呢

G1会进行三种GC

YoungGC  会拷贝eden和s1的存活对象到s2

MixedGC  对新生代和老年代进行回收, 使用的复制算法, 通过InitiatingOccupancy参数控制, 如果剩余的内存不足装下存活的对象, 会进行fullGC

fullGC 这个过程是非常耗时的. 

CMS和G1的区别

CMS的是并发标记清除, G1的标记整理, 是需要STW

CMS并发标记到重新标记使用的增量更新, G1是用的原始快照

CMS有新生代和老年代, G1没有物理的新生代和老年代, 只有逻辑的新生代和老年代

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/802517.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

0基础系列C++教程 从0开始 第三课

0基础系列C教程 从0开始 第三课来了! 这节课只是课后习题的解答 第四课讲变量 第二课课后习题 代码请自行写注释 写完后发在评论区 我会看的 习题代码: /*课后习题 不做注释 自行查看上节课的内容 题目:输出一下内容 114514 19191919 81…

前后端项目分离开发

问题说明: 开发人员同时负责前端和后端代码开发,分工不明确开发效率低前后端代码混合在一个工程中,不便于管理对开发人员要求高,人员招聘困难 解决方法: 前后端分离开发 介绍 前后端分离开发,就是在项…

【java】【面对对象高级2】继承

目录 1、概念 2、继承的执行原理 3、继承有啥好处 3.1 People父类 3.2 Teacher子类 3.3 主程序 4、继承的相关注意事项 4.1 权限修饰符 4.2 单继承、Object类 4.2.1 单继承 4.2.2 Object类 4.3 方法重写(声明不变、重新实现) 4.3.1 认识方法重写…

2023JAVA 架构师面试 130 题含答案:JVM+spring+ 分布式 + 并发编程》...

此文包含 Java 面试的各个方面,史上最全,苦心整理最全 Java 面试题目整理包括基JVM算法数据库优化算法数据结构分布式并发编程缓存等,使用层面广,知识量大,涉及你的知识盲点。要想在面试者中出类拔萃就要比人付出更多的…

selenium等待的三种方式(详细)

1.强制等待 time.sleep(3) 这种方式会是操作强行等待3s才会进行下一步操作,但是这种放法,可能会延长测试的时间,如果元素在1s中出现,就会浪费2s的时间,并且这种放法单次有效,每次需要等待元素的操作都需要…

如何打造亚马逊一流新品运营方案?

优化亚马逊新品运营方案需要商家采取一系列策略,以在激烈的市场竞争中脱颖而出。以下是一些针对亚马逊新品运营的优化建议: 1.深入了解产品和市场: 在上线新品之前,商家需要对产品和市场进行深入了解。了解目标客户群体、市场需…

重要通知|关于JumpServer开源堡垒机V2版本产品生命周期的相关说明

JumpServer(https://github.com/jumpserver)开源项目创立于2014年6月,已经走过了九年的发展历程。经过长期的产品迭代,JumpServer已经成为广受欢迎的开源堡垒机。 JumpServer堡垒机遵循GPL v3开源许可协议,是符合4A&a…

微信小程序radio单选按钮选中与取消

wxml <view bindtapcheckedTap><radio checked"{{checked}}">设为默认</radio> </view> wxss <style lang"less" > radio .wx-radio-input {border-radius: 50%; /* 圆角 */width: 24rpx;border: 2rpx solid #5e5e5f;hei…

网安周报 | 银行业成为开源软件供应链攻击的目标

网安周报是棱镜七彩推出的安全资讯专栏&#xff0c;旨在通过展示一周内发生的与开源安全、软件供应链安全相关攻击事件&#xff0c;让用户了解开源及软件供应链威胁&#xff0c;提高对安全的重视&#xff0c;做好防御措施。 1、银行业成为开源软件供应链攻击的目标 网络安全研…

nn.BCELoss与nn.CrossEntropyLoss

BCELoss与CrossEntropyLoss都是用于分类问题。可以知道&#xff0c;BCELoss是Binary CrossEntropyLoss的缩写&#xff0c;BCELoss是CrossEntropyLoss的一个特例&#xff0c;只用于二分类问题&#xff0c;而CrossEntropyLoss可以用于二分类&#xff0c;也可以用于多分类&#xf…

文档管理NAS储存安全吗?

关键词&#xff1a;私有化、知识管理系统、文档管理、群晖NAS、协同编辑 随着企业不断发展扩大&#xff0c;企业的知识文档也逐渐增多&#xff0c;很多企业方便管理及考虑数据安全问题会将文件数据储存至NAS。 但将企业文档数据放在NAS上就足够安全的吗&#xff1f; 天翎文档管…

【快应用】通用方法getBoundingClientRect的使用

【关键词】 快应用开发、通用方法、getBoundingClientRect 【背景】 快应用通用方法中提供了getBoundingClientRect方法来获取当前组件的布局位置&#xff0c;之前处理的快应用问题中&#xff0c;有个cp却把这种场景误解为可以获取到文字的宽度和高度&#xff0c;这是不合理的…

在线平面设计工具盘点,提升效率首选

在移动应用程序或网页UI设计项目中&#xff0c;在线平面图工具是必不可少的。市场上的在线平面图工具绘制软件丰富多样&#xff0c;层出不穷。作为一名UI设计师&#xff0c;有必要了解哪些在线平面图工具既简单又专业。本文将分享6种在线平面图工具&#xff0c;每种在线平面图工…

Vue 加载远程组件的解决方案

背景 最近的项目有一个加载远程组件的需求。基于此我对 Vue 加载远程组件的方案进行了研究&#xff0c;并且整理了两个可行的解决方案。 HTML 文件 umd 组件 这个方案是最简单、最容易实现的。组件以 umd 的格式进行打包&#xff0c;然后在 HTML 文件中直接使用。 <div…

Glide原理分析

工程目录图 Glide源码分析 - 缓存源码分析 活动缓存 &#xff1a;当前activity有效内存缓存&#xff08;LRU算法&#xff0c;核心linkhashmap&#xff09;,当前运行的整个app生命周都有效&#xff0c;有大小限制&#xff0c;防止app oom磁盘缓存&#xff0c;整个app都有效&…

汇编语言(第4版)实验9 根据材料编程

参考答案&#xff1a; ①经分析&#xff0c;完整程序代码如下。 assume cs:codesg,ds:datasgdatasg segment db welcome to masm! datasg endscodesg segment start: mov ax,0b800hmov es,axmov si,0722hmov ax,datasgmov ds,axmov cx,16mov bx,0s: mov al,ds:[bx]mov ah,0…

语音识别 — 特征提取 MFCC 和 PLP

一、说明 语音识别是一种技术&#xff0c;通过计算机和软件系统&#xff0c;将人们的口头语言转换为计算机可读的文本或命令。它使用语音信号处理算法来识别和理解人类语言&#xff0c;并将其转换为计算机可处理的格式。语音识别技术被广泛应用于许多领域&#xff0c;如语音助手…

Spring学习之Spring启示录

文章目录 OCP开闭原则依赖倒置原则控制反转依赖注入DI OCP开闭原则 什么是OCP&#xff1f; OCP是软件七大开发原则当中最基本的一个原则&#xff1a;开闭原则对什么开&#xff1f;对拓展开对什么闭&#xff1f;对修改关系 如果为了一个功能拓展&#xff0c;需要修改之前运行良…

项目播报 | 新基德携手璞华易研PLM,打造企业新一代研发管理平台

近日&#xff0c;“新基德PLM&#xff08;Product Lifecycle Management&#xff0c;产品生命周期管理&#xff09;项目”在新基德&#xff08;深圳&#xff09;电子有限公司&#xff08;以下简称&#xff1a;新基德&#xff09;正式启动。新基德是一家集手机研发、生产、销售、…

2023 数字生态发展大会,和鲸 ModelWhale 入选中国信通院“铸基计划”《高质量数字化转型产品及服务全景图》

7月27日&#xff0c;由中国信通院主办的“2023数字生态发展大会”暨中国信通院“铸基计划”年中会议在北京召开。本次大会重磅发布了《高质量数字化转型产品及服务全景图&#xff08;2023&#xff09;》&#xff0c;和鲸科技旗下数据科学协同平台 ModelWhale 成功入选&#xff…