JVM之基础概念(运行时数据区域、TLAB、逃逸分析、分层编译)
运行时数据区域
- JDK8 之前的内存布局

- JDK8 之后的 JVM 内存布局

JDK8 之前,Hotspot 中方法区的实现是永久代(Perm),JDK8 开始使用元空间(Metaspace),以前永久代中字符串常量、类静态变量移至堆内存,其他内容移至元空间,元空间直接在本地内存分配。
内存溢出

内存模型

TLAB
TLAB的全称是Thread Local Allocation Buffer,即线程本地分配缓存区,这是一个线程专用的内存分配区域。其本质还是Eden区域,只是从Eden区申请了一块私有区域,用三个指针进行管理:start、top 、end,其中 start 和 end 标识起始位置,top指目前已经使用到的位置,最大值为end。
可以把TLAB理解为一种Eden区域的空间分配策略,线程预先申请空间,后续的空间分配如果在自己独有的空间上进行,不存在竞争,可以大大提高分配效率。当然,线程申请独有空间还是存在竞争关系的,虚拟机采用CAS+失败重试保证操作的原子性。
那么,什么情况下才会在TLAB上直接分配?
先了解下JVM相关参数:
-XX:+UseTLAB:启用TLAB,默认开启
-XX:+TLABSize: 设置TLAB大小,JVM会在运行时不断调整,不建议手动设置
-XX:TLABRefillWasteFraction:TLAB允许浪费空间的比例,默认为64,refill_waste的默认值,运行时会不断调整
-XX:ResizeTLAB:自动调整TLABRefillWasteFraction阈值,默认开启
-XX:TLABWasteTargetPercent:设置TLAB空间所占用Eden空间的百分比大小,默认是1%
XX:+PrintTLAB:查看TLAB信息
分配规则:
- obj_size + tlab_top <= tlab_end:直接在TLAB空间分配对象
- obj_size + tlab_top > tlab_end
- tlab_free > tlab_refill_waste_limit:tlab剩余可用空间>tlab可浪费空间,当前线程不能丢弃当前TLAB,本次申请交由Eden区分配空间,下次遇到满足条件的小对象接着用
- tlab_free:剩余的内存空间,即tlab_end - tlab_top
- tlab_refill_waste_limit:允许浪费的内存空间,由-XX:TLABRefillWasteFraction决定,默认TLAB的1/64,运行时会不断调整
- tlab_free <= _refill_waste_limit:重新分配一块TLAB空间,在新的TLAB中分配对象,原TLAB就交给Eden管理
- tlab_free > tlab_refill_waste_limit:tlab剩余可用空间>tlab可浪费空间,当前线程不能丢弃当前TLAB,本次申请交由Eden区分配空间,下次遇到满足条件的小对象接着用
逃逸分析
public class EscapeAnalysis {
public static Object object;
public Object methodEscape1() { // 方法逃逸:方法返回值逃逸
return new Object();
}
public Object methodEscape2() { // 方法逃逸:作为参数传递到其它方法中
Object object=new Object();
xxx(object)
}
public void threadEscape1() {// 线程逃逸:赋值给类变量
object = new Object();
}
public void threadEscape2() { // 线程逃逸:其他线程中访问的实例变量
Object obj=new Object();
new Thread(() -> xxx(obj)).start();
}
public void eliminate1() { // o未逃逸,可自动清除锁
Object o=new Object();
synchronized (o){
xxx();
}
}
public void eliminate2() { // buffer未逃逸,append操作加锁可自动清除锁
StringBuffer buffer=new StringBuffer();
buffer.append("hello");
buffer.append("world");
buffer.append("!");
}
/**
* foo未逃逸,可通过标量替换进行优化
*/
publicint bar(int x) {
Foo foo = new Foo();
foo.a = x;
return foo.a;
// 优化后代码
int a = x;
return a;
}
}
- 逃逸分析缺点:不能保证逃逸分析的性能收益必定高于它的消耗
- 逃逸分析作用:
- 锁消除:-XX:+EliminateLocks开启(JDK8默认开启),-XX:-EliminateLocks关闭
- 标量替换:把不存在逃逸的对象拆散,将成员变量恢复到基本类型,直接在栈上创建若干个成员变量。分层编译()和逃逸分析在1.8中是默认是开启。参数:-XX:+EliminateAllocations
- 栈上分配:目前Hotspot并没有实现真正意义上的栈上分配,实际上是标量替换。栈上分配随着方法结束而自动销毁,垃圾回收压力减小
- XX:+DoExcapeAnalysis:开启逃逸分析,默认开启,可通过-XX:-DoEscapeAnalysis关闭
- XX:PrintEscapeAnalysis:查看分析结果
分层编译
从 Java 7 开始,HotSpot 默认采用分层编译的方式:系统执行初期热点方法优先使用C1编译器,以便尽快进入编译执行。随着时间推移,执行频率较高的代码再被C2编译器编译,以达到最佳性能。
C1、C2都是即时编译器,会将其中反复执行的热点代码,以方法为单位进行即时编译,翻译成机器码后直接运行在底层硬件之上。C2编译器需要收集大量统计信息用于编译优化,相对C1比较耗时,但运行效果更好。
热点方法是由JVM统计每个方法被调用的次数,超过多少次,就是热点方法。默认的分层编译应该是达到两千调C1,达到一万五调C2。
JVM之基础概念(运行时数据区域、TLAB、逃逸分析、分层编译)的更多相关文章
- 深入理解JAVA虚拟机之JVM性能篇---基础知识点(运行时数据区域)
一. 运行数据区域划分 各个数据区域功能如下: 1. 程序计数器: 较小的一块内存空间,可以看做是当前线程所执行的字节码的行号指示器,每条线程都有一个独立的程序计数器,各条线程之间计数器互不影响,独立 ...
- JVM运行时数据区域
上面已经聊过JVM是什么东东,也谈过了JVM内存的垃圾回收机制.这一篇博客我们来聊聊JVM运行时数据区域. JVM运行时数据区域由5块部分组成,分别是堆,方法区,栈,本地方法栈,以及程序计数器组成. ...
- 一. JVM发展史,运行时数据区域,四大引用
一.JVM的出现 JVM将字节码解释成不同os下的机器指令,有了jvm,java语言在不同平台上运行时不需要重新编译 虚拟机发展史 (1)Sun Classic classic jvm要么采用纯解释器 ...
- JVM 内存区域 (运行时数据区域)
JVM 内存区域 (运行时数据区域) 链接:https://www.jianshu.com/p/ec479baf4d06 运行时数据区域 Java 虚拟机在执行 Java 程序的过程中会把它所管理的内 ...
- JVM学习笔记(1)--运行时数据区域
运行时数据区域 相对于c,c++.程序设计时,java并不需要手动释放或者创建内存用于存放程序,这的确使得java开发变得容易和轻松,一旦有一天出现了内存泄漏或者内存溢出的问题,如果不了解JVM虚拟机 ...
- JVM 运行时数据区域划分
目录 前言 什么是JVM JRE/JDK/JVM是什么关系 JVM执行程序的过程 JVM的生命周期 JVM垃圾回收 JVM的内存区域划分 一.运行时数据区包括哪几部分? 二.运行时数据区的每部分到底存 ...
- JVM学习-运行时数据区域
目录 前言 运行时数据区 程序计数器 Java虚拟机栈 局部变量表 基础数据类型 对象引用 returnAddress 操作数栈 动态链接 方法返回地址 Java堆 方法区 类型信息 字段描述符 方法 ...
- JVM运行时数据区域详解
参考文章: <Java Se11 虚拟机规范> <深入理解Java虚拟机-JVM高级特性与最佳实践 第3版>- 周志明 本文基于Java Se 11讲解. 根据<Java ...
- JVM学习笔记:Java运行时数据区域
JVM执行Java程序的过程中,会使用到各种数据区域,这些区域有各自的用途.创建和销毁时间.根据<Java虚拟机规范>,JVM包括下列几个运行时数据区域,如下图所示: 其中红色部分是线程私 ...
随机推荐
- GUI编程
组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事 破解工具 简介 GUI的核心技术:Swing AWT 界面不美观 需要jre环境 为了了解MVC架构 了解监听. AWT 包 ...
- js Nullish Coalescing Operator
js Nullish Coalescing Operator 空值合并 const n = null ?? 'default string'; console.log(n); // "def ...
- Web 前端如何优雅的处理海量数据
Web 前端如何优雅的处理海量数据 Q: 如何在 Web 页面上处理上亿条后端返回的数据,并且保证 UI 展示的流畅性 A: 思路: 时间分片, 批处理,Buffer 缓存,虚拟滚动,Web Work ...
- HTMLMediaElement.srcObject & URL.createObjectURL & HTMLMediaElement.src
HTMLMediaElement.srcObject & URL.createObjectURL & HTMLMediaElement.src Uncaught TypeError: ...
- css & focus-within & pseudo class
css & focus-within & pseudo class demo :focus-within https://developer.mozilla.org/en-US/doc ...
- npm & cli & cp: no such file or directory
npm & cli & cp: no such file or directory empty files bug https://npm.runkit.com/hui-cli htt ...
- c++ 读取ASCII
void ReadASCII(BYTE* addr, size_t offset, char r[]) { size_t i = 0; char c; while (true) { c = *(add ...
- 高倍币VAST,如何破局NGK算力市场?
2020年,全球经济危机的爆发,无疑是给全球经济蒙上了一层阴影.而世界主要经济体也开启了无节制的放水,通过一轮又一轮的宽松货币政策,以刺激经济的发展.然而宽松的货币政策也加速了以美元为首的货币贬值,同 ...
- Mybatis-04 日志、分页
Mybatis-04 日志.分页 日志 1.日志工厂 如果数据库操作出现异常,就需要打印日志来排错. 日志工厂会把日志工作委托实现: SLF4J Apache Commons Logging Log4 ...
- Why GraphQL? 6个问题
Why GraphQL? 6个问题 GraphQL, 是一个API的标准: specification. 对于每个新技术, 要搞清楚的6个问题: 1.这个技术出现的背景, 初衷, 要达到什么样的目标或 ...