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.7.14 星期六 博客期:001 今天先是试着写一下博客,最近去青海旅游了,学习时间有点少,但空余时间还是有学习的,不管怎么样吧!先说一下我的这几天的成果——“Bignum”类,虽然很 ...
- Python基础之递归函数与二分法
一.递归函数 定义: 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. 我们来举个例子吧,比如:有个人问“egon”年龄,他说比“小大”大5岁,“小大”又说比“小保 ...
- Question Of AI Model Training
1 模型训练基本步骤 准备原始数据,定义神经网络结构及前向传播算法 定义loss,选择反向传播优化算法 生成Session,在训练数据进行迭代训练,使loss到达最小 在测试集或者验证集上对准确率进行 ...
- HTML&javaSkcript&CSS&jQuery&ajax(十)
HTML 1.SVG直接嵌入HTML网页 ,SVG 是使用XML描述2D图像的语言,Canvas通过JavaScript来绘制2D <svg xmlns="http://www.w3. ...
- python+selenium十四:xpath和contains模糊匹配
xpath可以以标签定位,也可以@任意属性: 如:以input标签定位:driver.find_element_by_xpath("//input[@id='kw']") 如:@t ...
- Django入门基础详解
本次使用django版本2.1.2 安装django 安装最新版本 pip install django 安装指定版本 pip install django==1.10.1 查看本机django版本 ...
- 制作linux下的.run安装包
前言 之前往linux上安装一个软件,都是以压缩包或者压缩包+shell的方法,这每次安装,都是先scp到某个目录, 解压,安装......稍微厉害的,会写个shell脚本.但是还是达不到真正的快速方 ...
- Pymysql-总结
背景:工作需要大量链接数据库进行一些操作查询,但是也会有出现异常情况 1.添加字段 1 ALTER TABLE app01_student ADD COLUMN Relation VARCHAR(25 ...
- PowerDesigner逆向生成MYSQL数据库表结构总结
由于日常数据建模经常使用PowerDesigner,使用逆向工程能更加快速的生成模型提高效率,所以总结使用如下: 1. 安装MYSQL的ODBC驱动 Connector/ODBC 5.1.1 ...
- 实战--Keepalived和LVS实现负载高可用
显然,只有上一篇的操作,在WEB运维技术中,只能承担一半的角色. 想像一下,如何LVS本身倒了,肿么办?后端的NGINX再多,也只能是干着急,请求过来不呀! 所以,在本篇时,我们来实现LVS永不倒, ...