我们在学习 G1 回收器的时候,一般我们都会接触到 TLAB 和 PLAB 这两个术语。它们都是为了提高内存分配效率而存在的,但它们和栈上分配有什么区别呢?今天,就让树哥带着大家盘一盘。

栈上分配

稍微了解过 Java 虚拟机内存结构的同学都知道,在 Java 虚拟机中有两个关键的存储数据节点,那就是:堆与栈。

其中堆是所有线程共享的一块内存,几乎所有对象的分配都在这块内存中。而栈则是线程自己私有的,只存储线程自己的局部变量等信息。每个线程都有自己的栈,栈信息无法在线程之间共享。

一般情况下,每个线程如果有新建的对象,那么会跟 JVM 申请在堆上创建对应的对象,而线程的栈则存储了指向堆对象的指针。每当一个线程想创建一个对象时,首先会请求 JVM,之后 JVM 进行协调,创建完成之后再告诉线程,线程最后将引用放到栈中。

在对象创建的这个过程,堆和栈之间的关系就像是列车的中央调度室和火车的关系。每次线程需要分配内存空间,都需要去到堆去申请空间,会耗费不少时间和精力。

这个时候有人就发现,线程的有些对象其实别人也不会访问到,放在堆中貌似也没什么大作用。于是他提出:对于这些其他线程不会访问的对象,我们能不能让线程自己分配在它自己的栈空间上?这样不就可以节省不少交互时间了么!

这个方法确实不错,如果能实现应该可以提高对象创建的时间,提高虚拟机的运行效率。

但问题是:我怎么知道哪些对象可以分配在栈上,哪些不行呢?

其实聪明的软件工程师们早就解决了这个问题了,他们新造了一个名字:逃逸分析。

那么什么是逃逸分析呢?

从字面意思上来讲,逃逸分析的目的是判断对象的作用域是否有可能逃出函数体。例如下面的代码就显示了一个逃逸的对象:

private static User user;
private static void hello(){u = new User();u.name = "java.top.select";u.website = "http://www.shuyi.me";
}

对象实例 user 是类的成员变量,可以被任何线程访问,因此它属于逃逸对象。但如果我们将代码稍微改动一下,该对象就可以线程非逃逸的了。

private static void hello(){User u = new User();u.name = "java.top.select";u.website = "http://www.shuyi.me";
}

可以看到 user 实例作用域只在 hello 函数中,不会被其他线程访问到,也不会访问。所以该 user 实例对象的作用域只在该函数中,因此它并未发生逃逸。对于这样的情况,虚拟机就有可能将其分配在栈上,而不在堆上。

看到这里,我相信许多人都应该明白了什么是栈上分配了。简单点说,就是将本来应该分配在堆中的对象,让其分配在线程私有的栈上。通过这种方式,减少垃圾回收的压力,提高虚拟机的运行效率。

TLAB

TLAB(Thread Local Allocation Buffer),即线程本地分配缓存。这是一块线程专用的内存分配区域,TLAB 占用的是 eden 区的空间。在 TLAB 启用的情况下(默认开启),JVM 会为每一个线程分配一块 TLAB 区域。

那么问什么需要 TLAB 呢?这是为了加速对象的分配!

由于对象一般分配在堆上,而堆事线程共用的,因此可能会有多个线程在堆上申请空间,而每一次的对象分配都必须线程同步,这样会降低内存分配的效率。

考虑到对象分配是非常常见的操作,于是 JVM 使用 TLAB 这样的线程转悠区域来避免多线程冲突,提高对象分配效率。

为了不至于导致 Eden 区被填充满,因此 TLAB 空间一般不会太大。因此大对象有可能无法在 TLAB 分配,只能直接分配到堆上。这其实是一种折中的设计哲学,因为大多数分配的对象都比较小,因此 TLAB 空间能满足大多数的需求。

PLAB

PLAB(Promotion Local Allocation Buffers),即晋升本地分配缓存。PLAB 的作用于 TLAB 类似,都是为了加速对象分配效率,避免多线程竞争而诞生的。 只不过 PLAB 是应用于对象晋升到 Survivor 区或老年代。与 TLAB 类似,每个线程都有独立的 PLAB 区。

对象内存分配流程

对于栈上分配与 TLAB 而言,其是有一定关系的。在进行对象内存分配的时候,首先会尝试进行栈上分配,接着尝试进行 TLAB 分配,接着判断是否可以直接进入老年代,最后不行的话再在 eden 区分配,如下图所示。

图片来自网络

总结

了解完栈上分配、TLAB、PLAB 之后,我们基本上可以清晰地回答如下问题。

什么是栈上分配,它解决什么问题?

栈上分配指的是对象直接在线程栈帧中进行分配,而不在堆中分配。它主要是为了解决多线程对象分配的低效问题,通过在栈上分配内存,避免了多线程之间的冲突,提高了对象的分配效率。但要注意的是,其只能分配较小对象,并且该对象必须不被其他对象线程引用。

什么是 TLAB,它解决什么问题?

TLAB 指的是线程本地分配缓存,其对应 Eden 区的某个区域,但这块区域只可以被该线程使用。

栈上分配和 TLAB 有啥区别?

TLAB 可以理解成是栈上分配的升级版本。栈上分配的对象只能被线程本身访问,但 TLAB 的对象可以被其他对象读取,但应该无法操作。通过 TLAB,它解决了部分需要多线程访问的对象分配效率问题,进一步提升了 JVM 的对象分配效率。

什么是 PLAB,它解决了什么问题?

PLAB 是为了在对象晋升到 Survivor 区或老年代的时候,提升对象的分配效率。其优化思路与 TLAB 类似,只是应用的地方不同。

JVM 的栈上分配、TLAB、PLAB 有啥区别?相关推荐

  1. java tlab_java虚拟机中容易和JVM栈上分配混淆的TLAB上分配

    今天介绍一个容易跟JVM栈上分配混淆的 TLAB 上分配. 1. TLAB 上分配 Java 程序会极其频繁的创建对象并为对象分配内存空间,一般情况下对象是分配在堆上的,堆又是全局共享的,所以会存在这 ...

  2. 栈上分配和TLAB的区别

    栈上分配 JVM中,栈上空间为线程私有,堆上空间为全局共享.所以大部分对象存在于堆上,线程通过栈上的引用指向堆上对象的内存地址.堆上没有任何引用关系的对象会被JVM标记后GC掉. 很多对象不存在逃逸现 ...

  3. 3.内存分配、逃逸分析与栈上分配、直接内存和运行时常量池、基本类型的包装类和常量池、TLAB、可达性分析算法(学习笔记)

    3.JVM内存分配 3.1.内存分配概述 3.2.内存分配–Eden区域 3.3.内存分配–大对象直接进老年代 3.3.1.背景 3.3.2.解析 3.4.内存分配–长期存活的对象进去老年代 3.5. ...

  4. JVM对象内存分配详细过程(栈上分配->TLAB->老年代->Eden区)

    一个类创建实例的时候,需要经过多个步骤,比如我们调用new的时候经过了哪些流程,本文就来详细分析下 专业术语 逃逸分析算法 逃逸分析其实就是分析java对象的动态作用域, 如果一个对象被定义之后,被外 ...

  5. GC分类、TLAB、逃逸分析、栈上分配、同步消除、标量替换

    GC分类 JVM的调优的一个环节,也就是垃圾收集,我们需要尽量的避免垃圾回收,因为在垃圾回收的过程中,容易出现STW(Stop the World)的问题,而 Major GC 和 Full GC出现 ...

  6. 关于栈上分配和TLAB的理解

    引言 我们知道,一般在java程序中,new的对象是分配在堆空间中的,但是实际的情况是,大部分的new对象会进入堆空间中,而并非是全部的对象,还有另外两个地方可以存储new的对象,我们称之为栈上分配以 ...

  7. JVM逃逸分析(同步省略、标量替换、栈上分配)

    在Java的编译体系中,一个Java的源代码文件变成计算机可执行的机器指令的过程中,需要经过两段编译,第一段是把.java文件转换成.class文件.第二段编译是把.class转换成机器指令的过程. ...

  8. (九)栈上分配与逃逸分析

    一.什么是逃逸? 逃逸是指在某个方法之内创建的对象,除了在方法体之内被引用之外,还在方法体之外被其它变量引用到:这样带来的后果是在该方法执行完毕之后,该方法中创建的对象将无法被GC回收,由于其被其它变 ...

  9. java标量替换_JAVA逃逸分析、栈上分配、标量替换、同步消除

    一.逃逸分析 逃逸分析是编译语言中的一种优化分析,而不是一种优化的手段.通过对象的作用范围的分析,为其他优化手段提供分析数据从而进行优化. 逃逸分析包括: 全局变量赋值逃逸 方法返回值逃逸 实例引用发 ...

最新文章

  1. Hinton等大牛要来中国授课,首个AI人才国际培养计划在北大启动
  2. Bad version number in .class file
  3. vb链接mysql登录界面_求大神!有谁会用VB设计用户登陆界面连接到数据库
  4. hbase regions_使用Regions ADF 11g进行Master Detail CRUD操作
  5. Linux基础提高_系统性能相关命令
  6. Thinkphp5内核大型程序员交流博客系统源码
  7. SpringMVC整合fastjson、easyui 乱码问题
  8. 资源 | 邓力、刘洋等合著的这本NLP经典书籍之情感分析中文版
  9. Android Studio 上传aar(Library)到JCenter
  10. 大华DVR IPC 常见问题
  11. PIC单片机IDE,IPE和PICkit3下载使用的几个坑
  12. 协同编辑--OT算法之外的世界
  13. 当我们给别人提意见时,要注意些什么?
  14. Android自定义-滑动缩放渐变填充曲线折线图表
  15. 如何使用R批量处理文件
  16. 计算机课 - 计算机科学导论
  17. ibm服务器如何查看内存型号,ibmx3650m4不识别|认不出内存怎么办|内存安装规则要求...
  18. “云控制服务”的设想
  19. 如何将数据传至服务器系统,怎样将数据传至云服务器
  20. Jacobi 和 Gauß-Seidel 迭代方法

热门文章

  1. pycharm远程debug报错:Couldn‘t apply path mapping to the remote file.
  2. 有趣的游戏编程学习网站
  3. CSS浏览器兼容总结篇
  4. 【操作系统】2、进程的描述和控制
  5. 塔望食业洞察|茶饮小料市场发展现状、消费洞察及趋势思考
  6. 网络提速降费助力“互联网+”发展
  7. 死磕源码系列【springboot之ConditionEvaluationReport记录报告和日志条件评估详情源码解析】
  8. gdb调试分析多线程死锁
  9. nefu java作业错题勘误
  10. 超微主板风扇调速,自定义调速