Skip to main content

moregeek program

面试官:怎么做JDK8的内存调优?-多极客编程

面试官:怎么做JDK8的内存调优?


面试官


看着面试官真诚的眼神,心中暗想看起来年纪轻轻却提出如此直击灵魂的问题。擦了擦额头上汗😓,我稍微调整了一下紧张的情绪😥,对面试官说:


在内存调优之前,需要先了解JDK8的内存区域是怎么划分的:


JDK8内存结构


JDK8的内存结构主要包括程序计数器(Program Counter Register)、虚拟机栈(Java Virtual Machine Stacks)、本地方法栈(Native Method Stacks)、(Java Heap)、元空间(Metaspace)。


其中又被划分为老年代(Old Generation)、年轻代(Young Generation),其中年轻代又被划分为一个Eden区和两个Survivor区


一边说着,一边拿起笔在纸上画了起来:


面试官:怎么做JDK8的内存调优?


画完以后,我又说:JDK8的内存调优主要针对的是堆和元空间。内存调优时常用到JVM参数有这些:


-server


JVM的server模式, 在多CPU服务器中性能可以得到更好地发挥。JDK的64位版本只支持server模式,因此在这种情况下,选项是隐式的。


-Xmx


指定堆所分配内存的最大值,等同于-XX:MaxHeapSize。不附加字母时,单位为byte,必须是1024的倍数,并且大于2MB;附加字母k或K时,表示单位为KB;附加字母m或M时,表示单位为MB;附加字母g或G时,表示单位为G。


下面的例子是使用不同的单位把堆所分配内存的最大值设置为1GB:


-Xmx1G
-Xmx1024M
-Xmx1048576K
-Xmx1073741824

-Xms


指定堆所分配内存的初始值,不附加字母时,单位为byte,必须是1024的倍数,并且大于1MB;附加字母k或K时,表示单位为KB;附加字母m或M时,表示单位为MB;附加字母g或G时,表示单位为G。如果不设置这个初始值,那么初始值将被设置为老年代和年轻代分配内存的大小的总和。


下面的例子是使用不同的单位把堆所分配的初始值设置为4GB:


-Xms4G
-Xms4096M
-Xms4194304K
-Xms4294967296

对于生产环境的部署,-Xms和-Xmx通常设置为相同的值。


-Xmn


指定堆的年轻代分配内存的初始值和最大值,不附加字母时,单位为byte;附加字母k或K时,表示单位为KB;附加字母m或M时,表示单位为MB;附加字母g或G时,表示单位为G。


堆的年轻代区域用于存放新生对象。与其他区域相比,在这个区域执行垃圾回收的频率更高。如果年轻代的内存太小,那么将执行许多次垃圾回收。如果年轻代的内存太大,那么执行完整的垃圾回收可能需要很长时间才能完成。一般建议把年轻代的大小保持在整个堆大小的1/2到1/4之间。


下面的例子是使用不同的单位把年轻代所分配内存的初始值和最大值设置为2GB:


-Xmn2G
-Xmn2048M
-Xmn2097152K
-Xmn2147483648

除了使用-Xmn选项设置年轻代的初始值和最大值,还可以使用-XX:NewSize设置年轻代的初始值,使用-XX:MaxNewSize设置年轻代的最大值。


-XX:NewRatio


指定老年代和年轻代空间大小的比率。默认为2,即老年代和年轻代空间大小的比率为2:1,年轻代占整个堆内存空间大小的1/3。下面的例子是把老年代和年轻代空间大小的比率设置为1:


-XX:NewRatio=1

另外,年轻代分配内存设置的优先级如下:


  1. 高优先级: -XX:NewSize/-XX:MaxNewSize
  2. 中优先级: -Xmn
  3. 低优先级: -XX:NewRatio

-XX:SurvivorRatio


指定Eden区和一个Survivor区的空间大小的比率。默认为8,即Eden区和一个Survivor区的空间大小为8:1,因为一共有两个Survivor区,所以Eden区占年轻代内存大小的80%。下面的例子是把Eden区和一个Survivor区的空间大小的比率设置为4:


-XX:SurvivorRatio=4

-XX:MetaspaceSize


指定元空间第一次触发垃圾回收的内存大小的阈值。当元空间内存占用不断增大,直到达到这个阈值时,就会触发一次垃圾回收。所以,适当的增大这个阈值,会减少垃圾回收的次数。默认值根据平台而定,一般情况下大约20.8MB。下面的例子是把元空间第一次触发垃圾回收的内存大小设置为256MB:


-XX:MetaspaceSize=256M

有一些小伙伴对这个参数有误解,造成不必要的麻烦。重申一下:-XX:MetaspaceSize不是元空间内存大小的初始值,不是元空间内存大小的初始值,不是元空间内存大小的初始值,重要的事情说三遍。


-XX:MaxMetaspaceSize


指定元空间所分配内存的最大值,默认是没有限制,取决于系统的可用内存量,理论上可以占满整个系统的内存。为了避免这种惨剧,影响系统上的其他应用,需要适当设置它的大小。下面的例子是把元空间所分配内存的最大值设置为512MB:


-XX:MaxMetaspaceSize=512M

面试官微笑地说:这些常用的内存调优参数总结的不错,可以结合这些参数写一个内存调优实例吗?


被面试官夸奖一下,我按捺住心中的喜悦说:当然可以。


内存调优实例


尽可能把堆内存的空间设置大一些,以减少垃圾回收的次数。假设服务器上的可用内存还有12GB,那么先指定堆所分配内存的最大值和初始值为8GB。一般情况下,年轻代内存大小需在整个堆大小的1/2到1/4之间,那么就指定年轻代内存大小为3GB。再把Eden区和一个Survivor区的空间大小的比率设置为4。元空间第一次触发垃圾回收的内存大小的阈值设置为256MB,一般情况下足够用。元空间所分配内存的最大值设置为512MB,为了避免极端情况下占用大量内存。另外,还需要明确指定JVM以server模式启动。


内存调优的参数基本敲定,用它启动一个名为one-more-study-0.0.1-SNAPSHOT.jar的jar文件:


java -server -Xmx8G -Xms8G -Xmn3G -XX:SurvivorRatio=4 -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -jar one-more-study-0.0.1-SNAPSHOT.jar

如果执行jmap -heap命令查看对应Java进程的内存配置和使用情况,应该是这样的:


Attaching to process ID 31828, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.251-b08

using thread-local object allocation.
Parallel GC with 8 thread(s)

Heap Configuration: #堆的内存配置
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
# 堆内存的最大值
MaxHeapSize = 8589934592 (8192.0MB)
# 年轻代内存的大小
NewSize = 3221225472 (3072.0MB)
# 年轻代内存的最大值
MaxNewSize = 3221225472 (3072.0MB)
# 老年代内存的大小
OldSize = 5368709120 (5120.0MB)
# 老年代和年轻代空间大小的比率
# 因为设置Xmn参数,该设置未生效
NewRatio = 2
#Eden区和一个Survivor区的空间大小的比率
SurvivorRatio = 4
# 元空间第一次触发垃圾回收的内存大小
MetaspaceSize = 268435456 (256.0MB)
# 元空间内存的最大值
MaxMetaspaceSize = 536870912 (512.0MB)
G1HeapRegionSize = 0 (0.0MB)

Heap Usage: # 堆的使用情况
PS Young Generation
Eden Space: # Eden区内存的使用情况
capacity = 2147483648 (2048.0MB)
used = 901945720 (860.16MB)
free = 1245537928 (1187.83MB)
42.000120505690575% used
From Space: # Survivor的From区内存的使用情况
capacity = 536870912 (512.0MB)
used = 0 (0.0MB)
free = 536870912 (512.0MB)
0.0% used
To Space: # Survivor的To区内存的使用情况
capacity = 536870912 (512.0MB)
used = 0 (0.0MB)
free = 536870912 (512.0MB)
0.0% used
PS Old Generation # 老年代内存的使用情况
capacity = 5368709120 (5120.0MB)
used = 0 (0.0MB)
free = 5368709120 (5120.0MB)
0.0% used

12047 interned Strings occupying 1045744 bytes.

听了我的回答后,面试官对我会心一笑,我仿佛还在她的眼神中看到了一丝敬仰。正所谓:万两黄金容易得,知心一个也难求,欲知后事如何,且听下回分解。

©著作权归作者所有:来自51CTO博客作者万猫学社的原创作品,请联系作者获取转载授权,否则将追究法律责任
面试官:怎么做JDK8的内存调优?
https://blog.51cto.com/u_6740480/5258373

Docker下,pinpoint环境搭建-多极客编程

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 在上一章《Docker下,极速体验pinpoint1.6.3》中,我们快速体验了pinpoint的监控和调用链跟踪的服务,本章我们一起来了解pinpoint环境的搭建过程,实战制作pinpoint服务端和客户端的镜像,让今后的部署过程更简单

面试官:怎么做JDK8的垃圾收集器的调优?-多极客编程

面试官:怎么做JDK8的垃圾收集器的调优? 看着面试官真诚的眼神,心中暗想看起来年纪轻轻却提出如此直击灵魂的问题。擦了擦额头上汗,我稍微调整了一下紧张的情绪,对面试官说: 在JDK8中有Serial收集器、Parallel收集器、CMS收集器、G1收集器这么几种收集器,需要根据实际硬件配置和业务需求进行选择调优。 如此浅显的回答,无法让面试官达到深入的要求,肯定不能满足面试官强烈的需求,果不其然

Http 前世今生-多极客编程

HTTP 协议在我们身边随处可见,只要上网就离不开它。不论是用浏览器还是 App,不论是看新闻、短视频还是听音乐、玩游戏,后面总会有 HTTP 在默默为你服务。 Http 协议是怎么来的?最开始是什么样子?又是如何一步步发展到今天,几乎统治了整个互联网世界 一起走向 HTTP 的世界,看历史长河中他是如何应运而生,如何适应当今的互联网,它又有什么局限性。 史前时期 20 世纪 60 年代,美国

#yyds干货盘点# Java 问题排查之Linux命令-多极客编程

Java 问题排查之Linux命令文本操作文本查找 - grepgrep常用命令:# 基本使用grep yoursearchkeyword f.txt #文件查找grep 'KeyWord otherKeyWord' f.txt cpf.txt #多文件查找, 含空格加引号grep 'KeyWord' /home/admin -r -n #目录下查找所有符合关键字的文件grep 'keyw

​SpringBoot--JWT的后端搭建前后分离-多极客编程

SpringBoot-零基础搭建前后端分离--后端搭建1.创建父项目verse 点击​​Create New Project​​选择 Maven ,选择本地安装的JDK, 点击 Next输入GroupID: com.verse 、ArtiactID:verse 点击 Finish创建完成后,删除​​src​​在​​pom.xml​​中添加依赖管理<?xml version="1.0" enc

netty系列之:可能有人听过ThreadLocal,但一定没人听过ThreadLocal对象池-多极客编程

简介 JDK中的Thread大家肯定用过,只要是用过异步编程的同学肯定都熟悉。为了保存Thread中特有的变量,JDK引入了ThreadLocal类来专门对Thread的本地变量进行管理。 ThreadLocal 很多新人可能不明白ThreadLocal到底是什么,它和Thread到底有什么关系。 其实很简单,ThreadLocal本质上是一个key,它的value就是Thread中一个map中存

Go 语言入门很简单:HTTP 包-多极客编程

引言Go 语言提供功能丰富的 ​​net/http​​​,实现了基础的 HTTP 中的 ​​client​​​ 和 ​​server​​​ 功能。在这一篇​​文章​​也有介绍一个基础的 HelloWorld 应用。如果没看过,也可以使用下面的代码创建一个简易 HTTP 的 ​​server​​ 服务:package mainimport ("log""net/http")type Handler

Docker下,pinpoint环境搭建-多极客编程

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 在上一章《Docker下,极速体验pinpoint1.6.3》中,我们快速体验了pinpoint的监控和调用链跟踪的服务,本章我们一起来了解pinpoint环境的搭建过程,实战制作pinpoint服务端和客户端的镜像,让今后的部署过程更简单

算法题每日一练---第35天: 机器人走迷宫-多极客编程

一、问题描述 一个机器人位于一个 m x n **网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 题目链接:机器人走迷宫 二、题目要求 考察 1.动态规划中等题型 2.建议用时5~15min 数据要求 1 &lt;= m, n &lt;=

[C++]C++入门到入土篇(一) HelloWorld 解析 && C++入门(一)-多极客编程

 在之前,我已经学完了C语言,数据结构初阶(C实现)。从本篇博客开始,正式进入C++的学习历程。C++的学习要结合之前C语言以及数据结构的知识,在学习C++的过程中顺便复习巩固已经学过的知识。愿自己能够持续努力,输出更多关于C++的优质文章。通过看完本篇解决以下问题:1. using namespace std;是什么意思?2. 你了解命名空间吗?会使用吗?3.  <<  符号是什么?

#yyds干货盘点# Java 问题排查之Linux命令-多极客编程

Java 问题排查之Linux命令文本操作文本查找 - grepgrep常用命令:# 基本使用grep yoursearchkeyword f.txt #文件查找grep 'KeyWord otherKeyWord' f.txt cpf.txt #多文件查找, 含空格加引号grep 'KeyWord' /home/admin -r -n #目录下查找所有符合关键字的文件grep 'keyw

​SpringBoot--JWT的后端搭建前后分离-多极客编程

SpringBoot-零基础搭建前后端分离--后端搭建1.创建父项目verse 点击​​Create New Project​​选择 Maven ,选择本地安装的JDK, 点击 Next输入GroupID: com.verse 、ArtiactID:verse 点击 Finish创建完成后,删除​​src​​在​​pom.xml​​中添加依赖管理<?xml version="1.0" enc