Java JVM堆空间的概述
Java JVM堆空间的概述
- 1.设置堆空间初始值和最大值
- 2.堆的核心概述
- 内存细分
- 3.堆空间大小的设置
- 4.新生代与老年代
- 5.图解对象分配的过程
- 6.常用调优工具
- 7.Minor GC、Major GC与Full GC
- 8.堆空间分代思想
- 9.内存分配策略
- 10.对象分配过程: TLAB
- 11.堆空间常用的VM参数
- 12.通过逃逸分析看堆空间的对象分配策略
- 1.堆是分配对象存储的唯一选择吗?
- 2.逃逸分析概述
- 3.逃逸分析:代码优化
- 4.逃逸分析的缺点
1.设置堆空间初始值和最大值
通过idea 的-VM参数设置,如下图:
2.堆的核心概述
内存细分
3.堆空间大小的设置
详情请看 Java SE8 官方文档 Ctrl+F 搜索 -Xms
通过JVM参数来设置堆空间的初始值
- -Xms用来设置堆空间(年轻代+老年代)的初始内存大小
- -X是jvm的运行参数
- ms是memory start
通过JVM参数来设置堆空间的最大值
- -Xmx用来设置堆空间(年轻代+老年代)的最大内存大小
堆的初始大小(以字节为单位)。
- 此值必须是1024的倍数且大于1 MB。在字母后面加上
k
或K
表示千字节,m
或M
表示兆字节,g
或G
表示千兆字节。 - 以下示例说明如何使用各种单位将分配的内存大小设置为6 MB:
- -Xms6291456
- -Xms6144k
- -Xms6m
- 如果未设置此选项,则初始大小将设置为为老一代和年轻一代分配的大小之和。可以使用
-Xmn
选项或-XX:NewSize
选项设置年轻代的堆的初始大小。
- 此值必须是1024的倍数且大于1 MB。在字母后面加上
开发中建议将初始堆内存和最大的堆内存设置成相同的值。
打印GC过程的细节
- JVM参数设置:-XX:+PrintGCDetails
添加代码测试**
public class HeapSpaceInitial {public static void main(String[] args) {//返回Java虚拟机中的堆内存总量long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;//返回Java虚拟机试图使用的最大堆内存量long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;System.out.println("-Xms : " + initialMemory + "M");System.out.println("-Xmx : " + maxMemory + "M");System.out.println("系统内存大小为:" + initialMemory * 64.0 / 1024 + "G");System.out.println("系统内存大小为:" + maxMemory * 4.0 / 1024 + "G");}
}
打印GC日志(详情信息看后期博客)
4.新生代与老年代
-XX:NewRatio:设置新生代与老年代的比例。
设置新老一代大小之间的比率。默认情况下,此选项设置为2。下面的示例演示如何将年轻/老人比率设置为1:1(这里就是年轻代占堆空间1:2,老年的占1:2)
-XX:NewRatio =3 //设置老年代占堆空间的3:4
-XX:SurvivorRatio:设置新生代中Eden区与survivor区的比例
-XX: -UseAdaptivesizePolicy :关闭自适应的内存分配策略( 暂时用不到)
Xmn:设置新生代的空间的大小。 ( 一般不设置)
5.图解对象分配的过程
6.常用调优工具
- JDK命令行
- Eclipse :Memory Analyzer Tool
- Jconsole
- Vi sual VM
- Jprofiler(暂时使用) 下载及破解
- Java Flight Recorder
- GCViewerGC Easy
7.Minor GC、Major GC与Full GC
年轻代GC(Minor GC) 触发机制:
- 当年轻代空间不足时,就会触发Minor GC,这里的年轻代满指的是
Eden代满,Survivor满不会引发GCI(每次Minor GC会清理年轻
代的内存。) - 因为Java对象大多都具备朝生夕灭的特性,所以MinorGC非常频
繁,一般回收速度也比较快。这一-定义既清晰又易于理解。 - Minor GC会引发STW,暂停其它用户的线程,等垃圾回收结束,用户线
程才恢复运行。
- 当年轻代空间不足时,就会触发Minor GC,这里的年轻代满指的是
老年代GC (Major GC/Fu11 GC)触发机制:
- 指发生在老年代的GC, 对象从老年代消失时,我们说“Major GC”或“Fu11 GC”
发生了。 - 出现了Major GC, 经常会伴随至少一.次的Minor GC (但非绝对的,在Paral1el
Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)。- 也就是在老年代空间不足时,会先尝试触发Minor GC。如果之后空间还不足,
则触发Major GC
- 也就是在老年代空间不足时,会先尝试触发Minor GC。如果之后空间还不足,
- Major GC的速度一般会比Minor GC慢10倍以上,STW的时间更长。
- 如果Major GC后,内存还不足,就报00M了。
- Major GC的速度- -般会比Minor GC慢10倍以上。
- 指发生在老年代的GC, 对象从老年代消失时,我们说“Major GC”或“Fu11 GC”
Fu11 GC,触发Fu1l GC执行的情况有如下五种:
- 调用System. gc()时,系统建议执行Fu1l GC,但是不必然执行
- 老年代空间不足
- 方法区空间不足
- 通过Minor GC后进入老年代的平均大小大于老年代的可用内存
- 由Eden区、survivor space0 (From Space)区向survivor space1 (To
Space)区复制时,对象大小大于To Space可 用内存,则把该对象转存到老年代,且
老年代的可用内存小于该对象大小;
说明: full gc是开发或调优中尽量要避免的。这样暂时时间会短一些。
8.堆空间分代思想
9.内存分配策略
如果对象在Eden(伊甸园区)出生并经过第一次MinorGC 后仍然存活,并且能被Survivor
容纳的话,将被移动到Survivor空间中,并将对象年龄设为1 。对象在
Survivor区中每熬过一次MinorGC ,年龄就增加1 岁,当它的年龄增加到- -定
程度(默认为15岁,其实每个JVM、每个GC都有所不同)时,就会被晋升到老年代
中。对象晋升老年代的年龄阈值,可以通过选项-XX: MaxTenuringThreshold来设置。
针对不同年龄段的对象分配原则如下所示:|
优先分 配到Eden
大对象直接分配到老年代
- 尽量避免程序中出现过多的大对象长期存活的对象分配到老年代
动态对象年龄判断
- 如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空
间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无须等到
MaxTenur ingThreshold中要求的年龄。
- 如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空
空间分配担保
- -XX: Handle PromotionFailure
10.对象分配过程: TLAB
为什么有TLAB ( Thread Local Allocation Buffer ) ?
- 堆区是线程共享区域,任何线程都可以访问到堆区中的共享数据
- 由于对象实例的创建在JVM中非常频繁,因此在并发环境下从堆区中划分内
存空间是线程不安全的; - 为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度。
什么是TLAB ?
- 从内存模型而不是垃圾收集的角度,对Eden区域继续进行划分,JVM为
每个线程分配了一个私有缓存区域,它包含在Eden空间内。 - 多线程同时分配内存时,使用TLAB可以避免一系列的非线程安全问题,
同时还能够提升内存分配的吞吐量,因此我们可以将这种内存分配方式称
之为快速分配策略。 - 据我所知所有OpenJDK衍生出来的JVM都提供了TLAB的设计。
- 从内存模型而不是垃圾收集的角度,对Eden区域继续进行划分,JVM为
TLAB分配过程:
11.堆空间常用的VM参数
-XX: +PrintFlagsInitial :查看所有的参数的默认初始值
-XX:+PrintFlagsFinal : 查看所有的参数的最终值(可能会存在修改,
不再是初始值)-Xms:初始堆空间内存 (默认为物理内存的1/64)
-Xmx:最大堆空间内存(默认为物理内存的1 /4)
Xmn: 设置新生代的大小。(初始值及最大值)
XX: +DoEscapeAnalysis ; 开启逃逸分析
XX:NewRatio:配置新生代与老年代在堆结构的占比
-XX:SurvivorRatio:设置新生代中Eden和SO/S1空间的比例
-XX:MaxTenuringThreshold:设置新生代垃圾的最大年龄
-XX: +PrintGCDetails:输出详细的GC处理日志
-XX:HandL ePromotionFailure:是否设置空间分配担保
-XX:+EliminateAllocations: 开启标量替换
12.通过逃逸分析看堆空间的对象分配策略
1.堆是分配对象存储的唯一选择吗?
- 在《深入理解Java虚拟机》中关于Java堆内存有这样一段描述:
随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导
致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。 - 在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。但是,有一一
种特殊情况,那就是如果经过逃逸分析(Escape Analysis) 后发现,一个对象并没有
逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无须
进行垃圾回收了。这也是最常见的堆外存储技术。 - 此外,前面提到的基于openJDK深度定制的TaoBaoVM,其中创新的GCIH (GC
invisible heap) 技术实现off -heap,将生命周期较长的Java对象从heap中移至
heap外,并且GC不能管理GCIH内部的Java对象,以此达到降低GC的回收频率和提升
GC的回收效率的目的。
2.逃逸分析概述
- 如何将堆上的对象分配到栈,需要使用逃逸分析手段。
这是一种可以有效减少Java程序中同步负载和内存堆分配压力的跨函数
全局数据流分析算法。 - 通过逃逸分析,JavaHotspot编译器能够分析出一个新的对象的引用的
使用范围从而决定是否要将这个对象分配到堆上。 - 当能够明确对象不会发生逃逸时,就可以对这个对象做一个优化,不将其分配到堆上,而是直接分配到栈上,这样在方法结束时,这个对象就会随着方法的出栈而销毁,这样就可以减少垃圾回收的压力。
- 逃逸分析的基本行为就是分析对象动态作用域:
- 当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有
发生逃逸。 - 当一个对象在方法中被定义后,它被外部方法所引用,则认为发生逃
逸。例如作为调用参数传递到其他地方中。
- 当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有
/*** 逃逸分析** 如何快速的判断是否发生了逃逸分析,大家就看new的对象实体是否有可能在方法外被调用。*/
public class EscapeAnalysis {public EscapeAnalysis obj;/*方法返回EscapeAnalysis对象,发生逃逸*/public EscapeAnalysis getInstance(){return obj == null? new EscapeAnalysis() : obj;}/*为成员属性赋值,发生逃逸*/public void setObj(){this.obj = new EscapeAnalysis();}//思考:如果当前的obj引用声明为static的?仍然会发生逃逸。/*对象的作用域仅在当前方法中有效,没有发生逃逸*/public void useEscapeAnalysis(){EscapeAnalysis e = new EscapeAnalysis();}/*引用成员变量的值,发生逃逸*/public void useEscapeAnalysis1(){EscapeAnalysis e = getInstance();//getInstance().xxx()同样会发生逃逸}
}
3.逃逸分析:代码优化
使用逃逸分析,编译器可以对代码做如下优化:
一、栈上分配:
将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。
二、同步省略:
如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。
三、分离对象或标量替换:
有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。
4.逃逸分析的缺点
- 关于逃逸分析的论文在1999年就已经发表了,但直到JDK 1.6才有实现,而且这项技
术到如今也并不是十分成熟的。 - 其根本原因就是无法保证逃逸分析的性能消耗一定能高于他的消耗。虽然经过逃逸分
析可以做标量替换、栈上分配、和锁消除。但是逃逸分析自身也是需要进行一系列复
杂的分析的,这其实也是一个相对耗时的过程。 - 一个极端的例子,就是经过逃逸分析之后,发现没有一个对象是不逃逸的。那这个逃
逸分析的过程就白白浪费掉了。 - 虽然这项技术并不十分成熟,但是它也是即时编译器优化技术中一个十分重要的手段。
注意到有一些观点,认为通过逃逸分析,JVM会 在栈.上分配那些不会逃逸的对象,这
在理论上是可行的,但是取决于JVM设计者的选择。据我所知,Oracle Hotspot
JVM中并未这么做,这一点在逃逸分析相关的文档里已经说明,所以可以明确所有的
对象实例都是创建在堆上。 - 目前很多书籍还是基于JDK 7以前的版本,JDK已经发生了很大变化,intern字符串.
的缓存和静态变量曾经都被分配在永久代上,而永久代已经被元数据区取代。但是,
intern字符串缓存和静态变量并不是被转移到元数据区,而是直接在堆上分配,所以
这一点同样符合前面一点的结论:对象实例都是分配在堆上。
Java JVM堆空间的概述相关推荐
- java虚拟机堆空间
堆是一个进程唯一的,是内存管理的核心区域 jvm启动时 堆 就会被创建,大小也就确定了,是jvm中管理的最大的一块内存,堆的大小是可以调节的 <java虚拟机规范>规定,堆可以处于物理上不 ...
- jvm堆空间的常用参数设置
- java堆空间(内存)
当Java程序开始运行时,JVM会从操作系统获取一些内存.JVM使用这些内存,这些内存的一部分就是堆内存.堆内存通常在存储地址的底层,向上排列.当一个对象通过new关键字或通过其他方式创建后,对象从堆 ...
- Java #JVM(HotSpot) 运行时数据区 #程序计数器(PC寄存器)#虚拟机栈(栈帧:局部变量表、操作数栈……)#堆……
目录 JVM中线程的说明 程序计数器(PC寄存器) 虚拟机栈 · 栈帧 ·· 局部变量表 ·· 操作数栈 ·· 动态链接 ·· 方法返回地址 ·· 本地方法栈 堆 · 查看堆的大小 · 堆的默认大小 ...
- java中的堆空间增加_Java堆内存的10个要点
当我开始学习Java编程时,我不知道什么是堆内存或堆空间,我甚至不知道当对象创建时,它们被放在了哪里.当我开始正式写一些程序后,我会经常遇到java.lang.outOfMemoryError的报错, ...
- 某团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:http://sina.lt/gqaM 最近网上出现一个美团 ...
- 美团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?
作者:gosaintmrc 来源:http://sina.lt/gqaM 最近网上出现一个美团面试题:"一个线程OOM后,其他线程还能运行吗?" 我看网上出现了很多不靠谱的答案.这 ...
- 美团面试:JVM 堆内存溢出后,其他线程是否可继续工作?
来源 | http://x7j.net/b8c06 最近网上出现一个美团面试题:"一个线程OOM后,其他线程还能运行吗?" 我看网上出现了很多不靠谱的答案.这道题其实很有难度,涉及 ...
- JVM 堆内存溢出后,其他线程是否可继续工作?
点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"加入公众号专属技术群 来源:http://sina.lt/gqaM 最近网上出现 ...
最新文章
- OzymanDNS 使用——perl 5.22没有成功。。。
- Android短消息备份闪退,Android Socket发送信息时闪退
- 环境变量和用户变量有什么区别?
- 微信小程序小模块界面,边框带阴影
- 如何用keras实现deepFM
- Python 数据科学入门
- 【渝粤题库】国家开放大学2021春1542投资学题目
- Android 内存泄漏分析(完)
- vue.js 模板语法
- Xshel和Xftp免费版
- 吉林大学超星MOOC学习通高级语言程序设计 C++ 实验01 顺序程序设计(2021级)
- 数字图像处理学习笔记(一)——数字图像处理概述
- 【报告分享】连锁经营行业全面费用管理数字化白皮书-亿欧汇联易(附下载)
- 变速恒频风电机组的优缺点_变速恒频双馈风力发电机的主要优点和基本原理
- 千千音乐付费音乐爬取--json数据的处理
- 微信小程序弹窗有输入框且可以使用名文和密文输入
- C# + OpenXML 生成 Word 文档(VS2015)
- WiFi无线网卡属性设置——英特尔无线适配器高级设置
- 《深入理解计算机系统》之浅析程序性能优化
- 电子信息(非全)考研分析——大连理工VS哈工程
热门文章
- UINO优诺:数字孪生可视化管理GIV,打造统览全局大视野
- archlinux下网易云音乐netease-cloud-music部分问题
- nodejs镜像问题如何设置镜像
- 西电计算机组织与体系结构实验,《计算机组织与体系结构》实验.doc
- 【论文投稿】Hindawi旗下4区Mobile Information Systems(misy)投稿详细步骤
- Egret(白鹭引擎)——Egret+fairyGui 实战项目入门
- [经验教程]2022京东618红包活动时间是什么时候开始什么时候结束及怎么领取京东618红包?
- 英语名篇——关于《论学习》的读后感
- 【electron】 打包应用修改图标和进程名字
- Drawing Rectangles(绘制矩形)