JVM之对象分配:栈上分配 & TLAB分配
1. Java对象分配流程

2. 栈上分配
2.1 本质:Java虚拟机提供的一项优化技术
2.2 基本思想: 将线程私有的对象打散分配在栈上
2.3 优点:
2.3.1 可以在函数调用结束后自行销毁对象,不需要垃圾回收器的介入,有效避免垃圾回收带来的负面影响
2.3.2 栈上分配速度快,提高系统性能
2.4 局限性: 栈空间小,对于大对象无法实现栈上分配
2.4 技术基础: 逃逸分析
2.4.1 逃逸分析的目的: 判断对象的作用域是否超出函数体[即:判断是否逃逸出函数体]
//user的作用域超出了函数setUser的范围,是逃逸对象
//当函数结束调用时,不会自行销毁user
private User user;
public void setUser(){
user = new User();
user.setId(1);
user.setName("blueStarWei");
} //u只在函数内部生效,不是逃逸对象
//当函数调用结束,会自行销毁对象u
public void createUser(){
User u = new User();
u.setId(2);
u.setName("JVM");
}
2.5 栈上分配示例
package com.blueStarWei.templet;
public class AllotOnStack {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
alloc();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
}
private static void alloc() {
User user = new User();
user.setId(1);
user.setName("blueStarWei");
}
}
2.5.1 上述代码调用了1亿次alloc(),如果是分配到堆上,大概需要1.5GB的堆空间,如果堆空间小于该值,必然会触发GC。
2.5.2 使用如下参数运行,发现不会触发GC
-server -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations
2.5.3 使用如下参数(任意一行)运行,会发现触大量GC
//不使用逃逸分析
-server -Xmx15m -Xms15m -XX:-DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations //不使用标量替换
-server -Xmx15m -Xms15m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:-EliminateAllocations
2.5.3.1 可以发现:栈上分配依赖于逃逸分析和标量替换
2.5.4 GC日志
[GC (Allocation Failure) 4095K->528K(15872K), 0.0025208 secs]
[GC (Allocation Failure) 4624K->552K(15872K), 0.0012518 secs]
[GC (Allocation Failure) 4648K->608K(15872K), 0.0009262 secs]
......(省略)
3718
2.5.4.1 GC日志解析
| 参数 |
作用 |
备注 |
| GC |
用来区分是 Minor GC 还是 Full GC 的标志(Flag). |
这里的 |
Allocation Failure |
引起垃圾回收的原因. | 本次GC是因为年轻代中没有任何合适的区域能够存放需要分配的数据结构而触发的. |
4095K->528K |
在本次GC之前和之后的年轻代内存使用情况. | 本次GC前,年轻代使用空间4095K, GC后年轻代使用空间为528K |
(15872K) |
年轻代的总的大小 | |
0.0025208 secs |
本次GC使用时间(单位:秒) |
2.5.5 JVM参数解析
| 参数 | 作用 | 备注 |
-server |
使用server模式 | 只有在server模式下,才可以弃用逃逸分析 |
-Xmx15m |
设置最大堆空间为15m | 如果在堆上分配,必然触发大量GC |
-Xms15m |
设初始对空间为15m | |
-XX:+DoEscapeAnalysis |
启用逃逸分析 | 默认启用 |
-XX:-DoEscapeAnalysis |
关闭逃逸分析 | |
-XX:+PrintGC |
打印GC日志 | |
| -XX:-UseTLAB | 关闭TLAB |
TLAB(Thread Local Allocation Buffer) 线程本地分配缓存区 |
-XX:+EliminateAllocations |
启用标量替换,允许对象打散分配到栈上 |
默认启用 |
-XX:-EliminateAllocations |
关闭标量替换 |
3. TLAB 分配
TLAB,全称Thread Local Allocation Buffer, 即:线程本地分配缓存。这是一块线程专用的内存分配区域。TLAB占用的是eden区的空间。在TLAB启用的情况下(默认开启),JVM会为每一个线程分配一块TLAB区域。
3.1 为什么需要TLAB?
这是为了加速对象的分配。由于对象一般分配在堆上,而堆是线程共用的,因此可能会有多个线程在堆上申请空间,而每一次的对象分配都必须线程同步,会使分配的效率下降。考虑到对象分配几乎是Java中最常用的操作,因此JVM使用了TLAB这样的线程专有区域来避免多线程冲突,提高对象分配的效率。
3.2 局限性: TLAB空间一般不会太大(占用eden区),所以大对象无法进行TLAB分配,只能直接分配到堆上。
3.3 分配策略:
一个100KB的TLAB区域,如果已经使用了80KB,当需要分配一个30KB的对象时,TLAB是如何分配的呢?
此时,虚拟机有两种选择:第一,废弃当前的TLAB(会浪费20KB的空3.4 间);第二,将这个30KB的对象直接分配到堆上,保留当前TLAB(当有小于20KB的对象请求TLAB分配时可以直接使用该TLAB区域)。
JVM选择的策略是:在虚拟机内部维护一个叫refill_waste的值,当请求对象大于refill_waste时,会选择在堆中分配,反之,则会废弃当前TLAB,新建TLAB来分配新对象。
【默认情况下,TLAB和refill_waste都是会在运行时不断调整的,使系统的运行状态达到最优。】
3.4 JVM参数解析
| 参数 | 作用 | 备注 |
| -XX:+UseTLAB | 启用TLAB | 默认启用 |
| -XX:TLABRefillWasteFraction | 设置允许空间浪费的比例 | 默认值:64,即:使用1/64的TLAB空间大小作为refill_waste值 |
| -XX:-ResizeTLAB | 禁止系统自动调整TLAB大小 | |
| -XX:TLABSize | 指定TLAB大小 | 单位:B |
4. 附件
4.1 User类
packagepackag com.blueStarWei.templet;
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
5. 参考文献
5.1 《实战Java虚拟机 - JVM故障诊断与性能优化》
5.2 栈上分配、TLAB : https://blog.csdn.net/yangsnow_rain_wind/article/details/80434323
5.3 快速解读GC日志 : https://blog.csdn.net/renfufei/article/details/49230943
JVM之对象分配:栈上分配 & TLAB分配的更多相关文章
- 【深入浅出-JVM】(7):栈上分配
概念 对那些作用于不会逃逸出方法的对象,在分配内存时,不在将对象分配在堆内存中,而是将对象属性打散后分配在线程私有栈内存上,这样随着方法调用结束,栈上分配打散的对象也被回收掉,不在增加 GC 额外压力 ...
- 请问什么时候对象分配会不在 TLAB 内分配
Java 对象分配流程 我们这里不考虑栈上分配,这些会在 JIT 的章节详细分析,我们这里考虑的是无法栈上分配需要共享的对象. 对于 HotSpot JVM 实现,所有的 GC 算法的实现都是一种对于 ...
- LWJGL3的内存管理,第二篇,栈上分配
LWJGL3的内存管理,第二篇,栈上分配 简介 为了讨论LWJGL在内存分配方面的设计,本文将作为该系列随笔中的第二篇,用来讨论在栈上进行内存分配的策略,该策略在 LWJGL3 中体现为以 Memor ...
- Java中的栈上分配
博客搬家自https://my.oschina.net/itsyizu/blog/ 什么是栈上分配 栈上分配是java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程 ...
- 【LWJGL3】LWJGL3的内存分配设计,第一篇,栈上分配
简介 LWJGL (Lightweight Java Game Library 3),是一个支持OpenGL,OpenAl,Opengl ES,Vulkan等的Java绑定库.<我的世界> ...
- Qt浅谈之一:内存泄露(总结),对于QWidget可以setAttribute(Qt::WA_DeleteOnClose),而且绝对不能手动删除栈上的对象
一.简介 Qt内存管理机制:Qt 在内部能够维护对象的层次结构.对于可视元素,这种层次结构就是子组件与父组件的关系:对于非可视元素,则是一个对象与另一个对象的从属关系.在 Qt 中,在 Qt 中,删除 ...
- new 的对象如何不分配在堆而分配在栈上(方法逃逸等)
当能够明确对象不会发生逃逸时,就可以对这个对象做一个优化,不将其分配到堆上,而是直接分配到栈上,这样在方法结束时,这个对象就会随着方法的出栈而销毁,这样就可以减少垃圾回收的压力. 如方法逃逸. 逃逸分 ...
- Java对象栈上分配
转自 https://blog.csdn.net/o9109003234/article/details/101365108 在学习Java的过程中,很多喜欢说new出来的对象分配一定在对上: 其实不 ...
- 深入探究JVM之对象创建及分配策略
@ 目录 前言 正文 一.对象的创建方式 二.对象的创建过程 对象在哪里创建 分配内存 对象的内存布局 三.对象的访问定位 四.判断对象的存活 对象生死 回收方法区 引用 对象的自我拯救 五.对象的分 ...
随机推荐
- Java的动手动脑(七)
日期:2018.11.18 博客期:025 星期日 Part 1:使用 Files.walkFileTree()来找出指定文件夹下大小大于1KB的文件 package temp; import jav ...
- Decimal integer conversion
问题 : Decimal integer conversion 时间限制: 1 Sec 内存限制: 128 MB 题目描述 XiaoMing likes mathematics, and he is ...
- Fiddler抓包1-抓firefox上https请求
前言 fiddler是一个很好的抓包工具,默认是抓http请求的,对于pc上的https请求,会提示网页不安全,这时候需要在浏览器上安装证书. 一.网页不安全 1.用fiddler抓包时候,打开百度网 ...
- easyui 布局之window和panel一起使用时,拉动window宽高时panel不跟随一起变化
项目开发中布局是每一个组件都由最外层的window和内部的至少一个panel组成,其他的细小组件再依次放到panel中. 问题:当拉动外部的window时我们希望内部的panel的宽高也跟着变化,但是 ...
- ajax之全局函数
1.全局函数:$.each(array,function(){1,value}),通过$/jQuery直接调用 对象函数:$("#name").val(); jQuery UI:$ ...
- 如何让谷歌浏览器支持跨域访问(AJAX) AJAX调试跨域接口
以谷歌最新版本为例(2018) 1.在电脑上新建一个目录,例如:C:\MyChromeDevUserData 2.在属性页面中的目标输入框里加上 --disable-web-security -- ...
- centos7.4/rehat7.0系统安装
以下是安装过程:(图解),以下是rehat为例 这里可以改为centos的镜像 之后就可以用了,记得做快照!!! 拓展:分离使用 效果:
- 步步為營-97-MyMVC3
說明: 解決另外一個不合理之處:通過控制器完成處理 1:在mvc文件夾下面添加一個工廠類文件DefaultControllerFactory 1.2進一步升級為抽象工廠 2 下一步如何規範Contro ...
- cnetos 7 mariadb 集群报错分析解答
1.故障1:通过查看/var/log/message 发现报错 2017-04-14 14:44:10 139845276428544 [ERROR] WSREP: It may not be saf ...
- javac选项以递归方式编译给定目录下的所有Java文件 - IT屋-程序员软件开发技术分享社区
http://www.it1352.com/539276.html #Linux $ find -name“* .java”> sources.txt $ javac @ sources.txt ...