90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(2)

Stella981
• 阅读 602

经常听到 Java 性能不如 C/C++ 的言论,也经常听说 Java 程序需要预热,那么其中主要原因是啥呢

面试的时候谈到 JVM,也有很多面试官喜欢问,为啥 Java 程序越执行越快呢

一般人都能回答上来,类加载,缓存预热等等,但是深入下去,最重要的却没有答上来,今天本系列文章就来帮助大家理解这个问题的关键。本篇文章是 TLAB 预热。

TLAB(Thread Local Allocation Buffer)线程本地分配缓存区,这是一个线程专用的内存分配区域。

90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(2)

既然是一个内存分配区域,我们就先要搞清楚 Java 内存大概是如何分配的。

90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(2)

我们这里不考虑栈上分配,这些会在 JIT 的章节详细分析,我们这里考虑的是无法栈上分配需要共享的对象

对于 HotSpot JVM 实现,所有的 GC 算法的实现都是一种对于堆内存的管理,也就是都实现了一种堆的抽象,它们都实现了接口 CollectedHeap。当分配一个对象堆内存空间时,在 CollectedHeap 上首先都会检查是否启用了 TLAB,如果启用了,则会尝试 TLAB 分配;如果当前线程的 TLAB 大小足够,那么从线程当前的 TLAB 中分配;如果不够,但是当前 TLAB 剩余空间小于最大浪费空间限制(这是一个动态的值,我们后面会详细分析),则从堆上(一般是 Eden 区) 重新申请一个新的 TLAB 进行分配。否则,直接在 TLAB 外进行分配。TLAB 外的分配策略,不同的 GC 算法不同。例如G1:

  • 如果是 Humongous 对象(对象在超过 Region 一半大小的时候),直接在 Humongous 区域分配(老年代的连续区域)。
  • 根据 Mutator 状况在当前分配下标的 Region 内分配

这里,我们先只关心 TLAB 分配。 对于单线程应用,每次分配内存,会记录上次分配对象内存地址末尾的指针,之后分配对象会从这个指针开始检索分配。这个机制叫做 bump-the-pointer (撞针)。 对于多线程应用来说,内存分配需要考虑线程安全。最直接的想法就是通过全局锁,但是这个性能会很差。为了优化这个性能,我们考虑可以每个线程分配一个线程本地私有的内存池,然后采用 bump-the-pointer 机制进行内存分配。这个线程本地私有的内存池,就是 TLAB。只有 TLAB 满了,再去申请内存的时候,需要扩充 TLAB 或者使用新的 TLAB,这时候才需要锁。这样大大减少了锁使用。

TLAB 初始化

90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(2)

TLAB 分配

90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(2)

GC 时 TLAB 回收与重计算期望大小

90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(2)

为何 Java 代码越执行越快 - TLAB预热

根据之前的分析,每个线程的 TLAB 的大小,会根据线程分配的特性,不断变化并趋于稳定,大小主要是由分配比例 EMA 决定,但是这个采集是需要一定运行次数的。并且 EMA 的前 100 次采集默认是不够稳定的,所以 TLAB 大小也在程序一开始的时候变化频繁。当程序线程趋于稳定,运行一段时间后, 每个线程 TLAB 大小也会趋于稳定并且调整到最适合这个线程对象分配特性的大小。这样,就更接近最理想的只有 Eden 区满了才会 GC,所有 Eden 区的对象都是通过 TLAB 分配的高效分配情况。这就是 Java 代码越执行越快在 TLAB 方面的原因。

每日一刷,轻松提升技术,斩获各种offer:

90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(2)

点赞
收藏
评论区
推荐文章
lucien-ma lucien-ma
3年前
Java里面的十万个为什么
Java里面的十万个为什么1.不是说JVM是运行Java程序的虚拟机吗?那JRE和JVM的关系是怎么样的呢?简单地说,JRE包含JVM。JVM是运行Java程序的核心虚拟机,而运行Java程序不仅需要核心虚拟机,还需要其他的类加载器,字节码校验器以及大量的基础类库。JRE除包含JVM之外,还包含运行Java程序的其
Wesley13 Wesley13
3年前
java克隆之深拷贝与浅拷贝
版权声明:本文出自汪磊的博客,未经作者允许禁止转载。Java深拷贝与浅拷贝实际项目中用的不多,但是对于理解Java中值传递,引用传递十分重要,同时个人认为对于理解内存模型也有帮助,况且面试中也是经常问的,所以理解深拷贝与浅拷贝是十分重要的。一、Java中创建对象的方式①:与构造方法有关
风斗 风斗
3年前
JMM 与 JVM的区别?很多人不清楚 ,一文带你了解得透透的
本篇文章我们主要分析一个大厂面试题:不要搞混JMM与JVM。在面试的时候,有一个问题经常被问到,那就是Java的内存模型,它已经成为了面试中的标配,是非常具有原理性的一个知识点。但是,有不少人把它和JVM的内存布局搞混了,以至于答非所问。这个现象在一些工作多年的程序员中非常普遍,主要是因为JMM与多线程有关,而且相对于底层而言,很多人平常的
Wesley13 Wesley13
3年前
Java面试官最爱的volatile关键字
在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性都牵扯出来,深入地话还可以考察JVM底层实现以及操作系统的相关知识。下面我们以一次假想的面试过程,来深入了解下volitile关键字吧!面试官:
Stella981 Stella981
3年前
Spring Boot 面试,一个问题就干趴下了!
前言随着SpringBoot使用越来越广泛,SpringBoot已经成为Java程序员面试的知识点,很多同学对SpringBoot理解不是那么深刻,经常就会被几个连环跑给干趴下了!比如下面这一段的SpringBoot问答:问:你觉得SpringBoot最大的优势是什么呢?答:SpringBoot的最大
Stella981 Stella981
3年前
90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(1)
麻烦大家帮我投一票(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Frank.juejin.cn%2F%3Fu%3D%25E5%25B9%25B2%25E8%25B4%25A7%25E6%25BB%25A1%25E6%25BB%25A1%25E5%25BC%25A0%25E5%259
Wesley13 Wesley13
3年前
Java线程 Top 50
不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎。大多数待遇丰厚的Java开发职位都要求开发者精通多线程技术并且有丰富的Java程序开发、调试、优化经验,所以线程相关的问题在面试中经常会被提到。在典型的Java面试中,面试官会从线程的基本概念问起,如:为什
Stella981 Stella981
3年前
2020年最新阿里、字节、美团、拼多多等一线大厂前端岗高频面试真题合集,面试轻松无压力
前言找工作还是需要大家不要紧张,干我们这一行的接触人本来就不多,难免看到面试官会紧张,主要是因为怕面试官问的问题答不上来,那时候不要着急,答不上了的千万不要胡扯一些,直接就给面试官说这块我还没接触到,以后如果工作当中遇到的话我可以很快的把这个问题给解决了,但是我们有了这篇文章,就不一样了,大厂面试的知识的点基本都有涉及,而大厂又是行业的标杆,多
可莉 可莉
3年前
2020年最新阿里、字节、美团、拼多多等一线大厂前端岗高频面试真题合集,面试轻松无压力
前言找工作还是需要大家不要紧张,干我们这一行的接触人本来就不多,难免看到面试官会紧张,主要是因为怕面试官问的问题答不上来,那时候不要着急,答不上了的千万不要胡扯一些,直接就给面试官说这块我还没接触到,以后如果工作当中遇到的话我可以很快的把这个问题给解决了,但是我们有了这篇文章,就不一样了,大厂面试的知识的点基本都有涉及,而大厂又是行业的标杆,多
Java HashMap 的工作原理详解
JavaHashMap的工作原理详解HashMap的工作原理是近年来常见的java面试题。几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如此特殊呢?是因为这道题