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

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

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

JDK8内存结构

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

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

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

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

文章持续更新,微信搜索「万猫学社第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

-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:

-Xmx4G
-Xmx4096M
-Xmx4194304K
-Xmx4294967296

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

-Xmn

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

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

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

-Xmx2G
-Xmx2048M
-Xmx2097152K
-Xmx2147483648

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

文章持续更新,微信搜索「万猫学社第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

-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

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

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

文章持续更新,微信搜索「万猫学社第一时间阅读,关注后回复「电子书」,免费获取12本Java必读技术书籍。

内存调优实例

尽可能把堆内存的空间设置大一些,以减少垃圾回收的次数。假设服务器上的可用内存还有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.

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

微信公众号:万猫学社

微信扫描二维码

关注后回复「电子书」

获取12本Java必读技术书籍

面试官:怎么做JDK8的内存调优?的更多相关文章

  1. JVM探究 面试题 JVM的位置 三种JVM:HotSpot 新生区 Young/ New 养老区 Old 永久区 Perm 堆内存调优GC的算法有哪些?标记清除法,标记压缩,复制算法,引用计数法

    JVM探究 面试题: 请你弹弹你对JVM的理解?Java8虚拟机和之前的变化更新? 什么是OOM?什么是栈溢出StackOverFlowError?怎么分析 JVM的常用调优参数有哪些? 内存快照如何 ...

  2. Spark Streaming 官网上提到的几点调优

    总的来说,需要考虑以下两点: 1. 有效地运用集群资源去减少每个批次处理的时间 2. 正确的设置batch size,以使得处理速度能跟上接收速度 一.  为了减少处理时间,主要有以下几个优化点: 1 ...

  3. JVM参数配置及内存调优

    一.JVM常见参数配置 堆内存相关参数 参数名称 含义 默认值   -Xms 初始堆大小 物理内存的1/64(<1GB) 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40% ...

  4. Spark 官网提到的几点调优

    1. 数据序列化 默认使用的是Java自带的序列化机制.优点是可以处理所有实现了java.io.Serializable 的类.但是Java 序列化比较慢. 可以使用Kryo序列化机制,通常比Java ...

  5. JVM、垃圾回收、内存调优、常见參数

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

  6. JVM 调优 内存调优 CPU 使用调优 锁竞争调优 I/O 调优

    Twitter 工程师谈 JVM 调优 2016年03月24日 10:22:30 wenniuwuren https://blog.csdn.net/wenniuwuren/article/detai ...

  7. JVM实用参数(四)内存调优

    理想的情况下,一个Java程序使用JVM的默认设置也可以运行得很好,所以一般来说,没有必要设置任何JVM参数.然而,由于一些性能问题(很不幸的是,这些问题经常出现),一些相关的JVM参数知识会是我们工 ...

  8. JVM学习笔记(四)------内存调优【转】

    转自:http://blog.csdn.net/cutesource/article/details/5907418 版权声明:本文为博主原创文章,未经博主允许不得转载. 首先需要注意的是在对JVM内 ...

  9. [hadoop] 集群启动和内存调优

    1.启动Hadoop集群 #首先查看下zoo.cfg里面配置的server.id和集群主机的id是否一致 #如果不一致会造成yarn控制不了从节点的启动 cat /home/hadoop/zookee ...

随机推荐

  1. day54 js基础

    目录 一.变量 二.数据类型 1 数值类型(number) 2 字符类型(string) 3 字符类型常用方法 4 布尔值(boolean) 5 null与undefined 6 对象 7 运算符 8 ...

  2. day44 初识数据库

    目录 一.数据的演变 二.数据库 三.MySQL 1 基本原理 2 重要概念介绍 3 安装 4 启动 5 sql基本语句 6 环境变量的配置及系统服务制作 7 关于密码 8 统一编码 9 基本sql语 ...

  3. 数据可视化之 图表篇(三)体验Power BI最新发布的AI图表:分解树

    在刚刚发布的11月更新中,PowerBI界面全新改版,采用和Office套件相似的Ribbon风格,除了这个重大变化,还发布了一个AI黑科技图表:分解树(Decomposition Tree). 无论 ...

  4. 目录(Python基础)

    Python之介绍.基本语法.流程控制 Python之列表.字典.集合 Python之函数.递归.内置函数 Python之迭代器.装饰器.软件开发规范 Python之常用模块学习(一) Python之 ...

  5. 用Vue实现一个简单的图片轮播

    本文已收录至https://github.com/likekk/studyBlog欢迎大家star,共同学习,共同进步.如果文章有错误的地方,欢迎大家指出.后期将在将GitHub上规划前端学习的路线和 ...

  6. 简单实用的办公软件导航网站,IT经理必备工具

    最近非常忙,因为公司上线了业财一体化系统.今天分享一个非常实用的办公软件导航网站,节省了我很多百度的时间. 快氪导航,让软件服务更简单. 一.办公软件导航 站长已经按照功能进行了分类:协同办公,流程审 ...

  7. 深入浅出ReentrantReadWriteLock源码解析

    读写锁实现逻辑相对比较复杂,但是却是一个经常使用到的功能,希望将我对ReentrantReadWriteLock的源码的理解记录下来,可以对大家有帮助 前提条件 在理解ReentrantReadWri ...

  8. 利用华为eNSP模拟器实现vlan之间的通信

    eNSP交换机配置VLAN 1. 搭建网络拓扑结构 运行eNSP>新建拓扑>搭建如下图的拓扑结构>启动设备.利用调色板将划分的vlan进行区分. 2. pc机IP地址配置 pc1的I ...

  9. 感知机算法(PLA)代码实现

    目录 1. 引言 2. 载入库和数据处理 3. 感知机的原始形式 4. 感知机的对偶形式 5. 多分类情况-one vs. rest 6. 多分类情况-one vs. one 7. sklearn实现 ...

  10. 题解 洛谷 P3639 【[APIO2013]道路费用 】

    不难想到可以\(2^k\)去枚举\(k\)条新边的选择方案,然后加入原图中的边来使图连通,用当前方案的收益去更新答案,但是这样复杂度过不去. 可以先把\(k\)条新边都连上,然后再加入边权从小到大排序 ...