JVM原理和调优(读这一篇就够了)

article/2025/8/19 22:59:07

前言

 

抛2个问题:

1、export JAVA_OPTS="-Xms256m -Xmx512m -Xss256m -XX:PermSize=512m -XX:MaxPermSize=1024m  -Djava.rmi.server.hostname=136.64.45.24 -Dcom.sun.management.jmxremote.port=9315 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"

---上面的"-Xms256m -Xmx512m -Xss256m -XX:PermSize=512m -XX:MaxPermSize=1024m“分别是什么意思

 

2、为什么调整上面这几个参数就能让java程序不卡顿,或者不报错oom

 

3、java.lang.OutOfMemoryError: Java heap space和java.lang.StackOverflowError是否熟悉,分别表示了什么错误,背后出现了什么问题

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一、JVM内存模型

  • 堆:所有new对象都放在堆里,这也是JVM优化的重点。

  • 栈:也叫线程栈,是每个线程独立分配的内存空间,存储的包括局部变量,操作数,动态链接,方法出口。它和堆的关系其实是堆的指针引用。

  • 本地方法栈:为虚拟机用到的Native方法服务。Native方法是java通过JNI直接调用本地C/C++库,可以认为是暴露给java的本地接口。

  • 方法区(元空间):类装载系统会把class信息放到方法区,通过字节码引擎执行。会放常量(运行时常量池,那么什么是静态常量池),静态变量,类元信息。jdk8以后就叫元空间。

  • 程序计数器:记录执行的代码行数的行号,比如线程暂停回来后,继续执行,就需要读取行号,继续向下执行

(一)栈的核心组成部分

  • 局部变量表: 用于存放方法中的局部变量和参数

  • 操作数栈: 用于存放方法执行过程中产生的中间结果

  • 动态链接:方法区里面的符号引用转为直接引用(即:给出地址)

  • 方法出口:记录当前执行方法执行完毕后返回主方法的下一行位置

 

(二)堆

所有的new对象最开始都放到Eden(伊甸)区,当Eden区沾满之后,JVM会进行一次minor gc,将发现依然存活的对象放到Survivor区,同时讲分代年龄+1(存储在object header里面),会清理eden和form区域,通过复制等算法再次将存活对象放到to区域,依次类推来回复制,当分代年龄达到15时,会挪到老年代,比如静态变量,数据库连接池,缓存就属于“老不死”。当老年代内存被占满时,就会触发full gc,full gc会对整个堆进行垃圾回收,因此非常耗时,时间很长,我们要尽量降低full gc的频次。

题外话:minor gc如何进行垃圾回收呢,这里面运用到一个可达性分析算法,里面有一个GC roots根的概念很关键,要理解一下,gc会根据该算法找出该对象的整条GC root链,定义为有效存活对象,会移动到survivor区域;剩下的对象由于找不到对象引用,因此定义为无效对象,从而进行回收。具体如下:

 

(为什么年轻代使用复制算法,老年代使用标记-清除算法?)

 

还有一种情况,只要伊甸区移动的内存大于存活区的1/2时,会直接放到老年代。

 

当old区内存满了后,就会触发full gc,但是发现引用还在(list还是运行),因此没法回收,但是死循环又一直在new对象,old区无内存可用,于是就OOM。

在full gc的时候针对整个heap进行寻找垃圾对象,因此会停顿用户线程(STW)。为什么要停止呢,如果不停止的话,意味着回收线程和用户线程同步执行,回收线程会认为用户线程的内存不是垃圾对象,因此不予理会,但如果用户线程很快执行完,它使用的对象就变成垃圾对象了,这时候回收线程不知道该如何处理,因此为了更好的控制内存,full gc的时候,必须暂停用户线程,回收完成后,再恢复用户线程。因此问题就出现了,如果频繁的full gc,而且收集时间非常长(因为针对整个堆内存回收)就会频繁的停止用户线程,导致系统功能暂时不可用,也就是卡顿现象或无响应。因此优化的点就一目了然: 减少full gc次数,让年轻代去收集释放垃圾对象。

 

二、JVM调优

为什么调优其实上面已经提前说了,所以我们调优的目的是什么呢?就是让系统更加的丝滑,让用户体验变得更好。

以下是一个亿级流量网站的一个并发计算过程demo图:

以下是关键数据计算:

  • 日活:1E/20 = 500W。要估算每个人一天的日点击数。

  • 日均订单:50W。这里要找业务确定转化率。

  • 大促并发数:50W/50s = 1000单左右。这里要估算并发时间,这里拍脑袋是1分钟内。

  • 单机并发数:1000/n。n表示是机器节点。

  • 每单请求的数据量:1kb * 1000/n。1kb是单个请求的data大小,这个研发可以根据请求data json算出来。

  • 单机的内存使用:300kb * 20 * 10 = 60M。300kb是n=3,20是下单逻辑中会有加减库存,优惠券,积分系统接口,10是订单查询等其他外部操作。

初始化jvm配置如下:

 

对应的jvm内存模型是:

 

  1. 每一秒产生60M对象,均放到eden区

  2. 到第13秒时,eden区内存即将占满(60*13 =780M),触发minor gc

  3. 这时候会对前12秒的对象进行回收,第13秒产生的对象由于还在执行,因此判断为有效对象,会被移动到S0区

  4. 这时候会触发jvm另外一个机制--动态年龄判断,即发现该对象大小大于survivor区内存大小的50%,会直接进入old区。因此该60M对象会直接移动到old区。因此会出现每过13秒,会有60M数据进入old区

  5. 所以old区大概多久会被占满,2000M/60 *13 = 433s。也就是大概433s后就会触发一次full gc

  6. 因此问题来了,如果这个大促持续数个小时,而每隔7分钟就执行一次full gc,势必影响用户体验和性能。那么怎么优化呢

解决策略:我们完全可以把old区的这60M对象让它在survivor区就回收,减少old区的full gc次数。因此我们需要对jvm参数进行优化配置。(阿里面试题:能否对JVM调优,使其几乎不发生full gc。答案是能)

将年轻代的内存调大(-Xmn2048M)

 

所以,jvm优化后的内存分配模型就出来了:

 

 

 

2个好处:

  • 原来13秒就minor gc,现在延长到25秒

  • 60M对象会在survivor区就会被回收,不会跑到old区触发full gc

 

 

(全文完)

(喜欢视频的可以去读下这个:https://www.bilibili.com/video/av79368741/?p=5)

 

 

 


http://chatgpt.dhexx.cn/article/0QihD6F4.shtml

相关文章

JVM工作原理

JVM的生命周期 (1)两个概念:JVM实例和JVM执行引擎实例 JVM实例对应了一个独立运行的java程序,它是进程级别的 JVM执行引擎实例则对应了属于用户运行程序的线程,它是线程级别的 (2)VM实例的诞生…

JVM原理与实战

JVM原理 类加载流程和内存分配栈帧操作一、JVM垃圾回收算法主动加载的几种方式?符号引用和直接引用1.1 什么是垃圾(Garbage Collection)回收?1.2 引用计数法(Reference Conting)1.3 标记清除法 *(Mark - Sweep)1.4 复制算法 *(Copying)1.4.1 复制算法在JVM中的应用1.…

jvm原理与性能调优

文章目录 一、JVM内存结构 1.运行时数据区 2.直接内存 二、JVM中的对象 1.对象的创建 2.对象的内存布局 3.对象的访问定位 三、垃圾回收算法和垃圾回收器 1. 如何判断对象是已死 2.分代回收理论 3.垃圾回收算法 4.垃圾收集器 四、JVM执行子系统 1.Class文件结构 2.类加载机制 3…

什么是JVM?深入解析JVM原理!

一、JVM是什么? JVM是Java Virtual Machine(Java虚拟机)的缩写,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM屏蔽了与操作系统平台相关的信息,使得Java程序只需要生成在J…

全面阐述JVM原理

一 JVM入门 1. 什么是JVM JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码…

JVM原理

JVM原理 一.jvm简介 JVM是Java Virual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,他是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组…

JVM原理详解

主题内容: 1.JVM 内存区域概览 2.堆区的空间分配是怎么样?堆溢出的演示 3.创建一个新对象内存是怎么分配的? 4.方法区 到 Metaspace 元空间 5.栈帧是什么?栈帧里有什么?怎么理解? 6.本地方法栈 7.程序…

JVM的运行原理

目录 1.概念 2.JVM运行机制 3.JVM执行流程 4.JVM运行时数据区 什么是线程私有? OOM(内存溢出) 4.1 堆:也叫运行时数据区,线程共享 4.2 方法区:线程共享 4.3 Java虚拟机栈:线程私有,描…

JVM的原理

JVM原理(一) 1、JVM总体结构图 2、JVM堆结构图以及分代 复制算法: 1、新生成的对象存放在Eden区和from区 2、当Eden区内存不够,虚拟机将发起一次MinorGC 3、GC进行时,Eden区中所有存活的对象都会被复制到to区 4、年龄阀值达到15的会被放到老年…

JAVA虚拟机JVM工作原理

提起JAVA,都知道它有个虚拟机,因此可以跨平台,一次编写,到处运行。但具体原理是咋样的?身为JAVA小白,岂可不知! 一、原理 二、结构 1、类加载器 2、执行引擎 3、运行时数据区域一、原理 JVM实现…

JVM 运行机制及其原理

最近出去面试,总被问到Java JVM相关的东西,什么JVM的内存模型、JVM的内存分配、内存回收、内存回收算法…搞得我一头雾水,早些年还看过一些,蹭着有时间给大家也给自己总结下JVM相关的知识。 JVM JVM是Java Virtual Machine&…

JVM原理-超详细总结

JVM概念 JVM是java的核心和基础在java编译器和os平台之间的虚拟处理器。它是一种利用软件方法实现的抽象的计算机基于下层的操作系统和硬件平台,可以在上面执行java的字节码程序。java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经…

2022年iOS最新面试(底层基础)问题答案

文章目录 Runloop 1、RunLoop 的本质是什么?2、Runloop和线程是什么关系?3、Runloop的底层数据结构是什么样的?有几种 运行模式(mode)?每个运行模式下面的 CFRunloopMode 是哪些?他们分别是什么…

2019年面试必备:iOS 面试题大全(附答案)

这个栏目将持续更新–请iOS的小伙伴关注! 1、多线程的应用 2、GCD实现多个请求都完成之后返回结果 3、A、B两个int数组,得到A数组中B数组不包含的元素 4、事件传递链,页面上一个按钮,按钮和它的superView有一样的action,为什么只执行button的…

iOS 多线程面试题

没有比这里更全的了,看我就好了 面试官😃 :你了解进程吗?谈谈你对进程和线程的理解? 不谈进程,线程无从谈起。要了解什么是线程,我们先需要理解什么是线程。 秒懂百科 😃 以上百科&…

2020,300道高级iOS开发面试题(最新整理)

这个栏目将持续更新–请iOS的小伙伴关注! 一:知名大厂iOS开发面试题篇 1、腾讯—最新iOS面试题总结 2、百度—最新iOS面试题总结 3、头条—最新iOS面试题总结 4、阿里—最新iOS面试题总结 5、美团—最新iOS面试题总结 6、某大厂—最新iOS面试题总结 7、抖音–最新i…

iOS经典面试题大全

1.INTERVIEW 共勉 作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:638302184,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 与2800i…

2021年,整理的iOS高频面试题及答案(总会有你需要的)

推荐阅读:关于iOS面试题汇总(栏目持续更新) 各位最近应该忙于跳槽与面试吧,毕竟金三银四,珍惜好机会,预祝大家面试顺利通过,迎接大厂offer。有需要资料可以私聊我了解 从输入url到页面展示到底发生了什么 1、输入地…

iOS面试题 2016版

2015-1-3 达内纪老师 GitHub,CSDN博客 说明: 最近为达内学员整理面试题。发现网上的面试题和答案基本都是抄来抄去的,甚至很多答案都是错误的。 所以整理了常见的面试题,对答案重新进行了筛选整理。 如果答案有错漏或者更好的答案…

iOS面试题系列之常见算法

iOS面试中熟悉常见算法 1、 对以下一组数据进行降序排序(冒泡排序)。“24,17,85,13,9,54,76,45,5,63” int main(int argc, char *argv[]) {int …