🏆【JVM技术专区】「难点-核心-遗漏」TLAB内存分配+锁的碰撞(技术串烧)!
JVM内存分配及申请过程
当使用new关键字或者其他任何方式进行创建一个类的对象时,JVM虚拟机需要为该对象分配内存空间,而对象的大小在类加载完成后已经确定了,所以分配内存只需要在Java堆中划分出一块大小相等的内存,JVM虚拟机中有指针碰撞和空闲列表两种方式分配内存。
指针碰撞方式
如果Java堆中内存是规整排列的,所有被用过的内存放一边,空闲的可用内存放一边,中间放置一个指针作为它们的分界点,在需要为新生对象分配内存的时候,只要将指针向空闲内存那边挪动一段与对象大小相等的距离即可分配。
代表GC回收器
ParNew,Serial,G1
空闲列表方式
如果Java堆中内存不是规整排列的,用过的内存和可用内存是相互交错的,这种情况下将不能使用指针碰撞方式分配内存,Java虚拟机需要维护一个列表用于记录哪些内存是可用的,在为新生对象分配内存的时候,在列表中寻找一块足够大的内存分配,并更新列表上的记录。
代表GC回收器
cms
Java虚拟机选择策略
Java虚拟机采用哪种方式为新生对象分配内存,取决于所使用的垃圾收集器,当垃圾收集器具有整理过程时,虚拟机将采用指针碰撞的方式;当垃圾收集器的回收过程没有整理过程时,则采用空闲列表方式。
现在虚拟机栈进行分配
此部分属于两部分的分配机制,当JVM创建线程Thread对象:
直接分配:局部变量、形式参数表。
优化分配:逃逸分析(栈上分配、标量替换等功能)。
如果完成分配之后,则结束内存分配,否则出现分配失败,或者无法进行分配操作后,会进入堆内存方式的分配。
新生区-Eden区的分配

TLAB内存的分配策略
上面刚刚说过了,主要有两种内存分配机制:如果采用指针碰撞法,则会出现性能问题和指针分配冲突的问题.,JVM虚拟机采用优化的手段,就是TLAB(ThreadLocal Allocation Buffer)预先分配了内存块。
总体内存分配流程策略

如果TLAB内存分配失败或者空间不足,则JVM会试图为相关Java对象在Eden中初始化一块内存区域,当Eden空间足够时,内存申请结束
当如果出现了Eden区内存无法进行分配,则会发生相关MinorGC(JVM试图释放在Eden中所有不活跃的对象(Minor GC),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区)。
此时Survivor区被用来作为Eden及old的中间交换区域,如果Survivor不足以放置eden区的对象 ,会进行担保分配,或者已经达到直接晋升到老年代的条件后,此时如果old区有空闲,Survivor区的对象会被移到Old区。
当old区空间不够时,JVM会在old区进行major collection;
完全垃圾收集后,若Survivor及old区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现"Out of memory错误";
- jvm优先分配在eden区
- 当Eden空间足够时,内存申请结束。
JVM锁的膨胀执行流程机制

无锁节点/偏向锁阶段
创建线程的时候在程序执行到同步代码块的时候,首先会基于上面说到的内存分配策略进行分配内存,此时会当当前线程获取到了相关锁资源的时候,因为属于无锁状态下转换为偏向锁:
无锁标记头

偏向锁标记头

- 会将相关的当前线程的线程ID赋值到相关的标记字段中。
- 为了提高性能以及栈空间可以获取相关的竞争数据,会将对象头的标记字段(Markword)拷贝到栈空间内部(Lock Record)锁记录。
轻量级锁阶段
竞争到锁的线程
与此同时,当另外一个线程同时也去竞争该资源的时候,需要进行竞争,因为在获取资源的时候,底层采用CAS机制取获取相关的资源标志,一旦获取成功,便可以通过偏向锁标识进行判断是否属于当前的锁owner线程。
当发现不属于偏向锁的线程进来竞争的时候,此时会产生竞争关系,因为同一时刻,只能允许一个线程获取资源,当前获取资源的线程会因为有其他线程也争抢过该资源,故此将java对象头中的锁字段改为00,如下图所示:
未竞争到锁的线程
当发生线程争抢CAS机制失败的时候,会进行相关的自旋机制,进行尝试下一次进行争抢到锁。
重量级锁阶段
未竞争到锁的线程
当超过自旋的线程一直处于自旋,且超过了自旋阈值之后,变会升级成为了重量级锁。
或当更多的线程都处于争抢状态且属于自旋锁机制之后(出现了大量的轻量级锁之后),便会升级未重量级锁。
直到被唤醒重新镜像竞争锁资源信息。
升级为重量级锁的结果会将线程的标志位置为10
此时不会在进行自旋CAS争抢 ,而是直接阻塞执行(采用底层mutex/Fast Mutex锁进行暂停中断线程的执行)。
竞争到锁的线程
当锁标记因为发生变化,成为了重量级锁,所以,线程会同步自己的所记录,发现不一致,同步为重量级锁状态后,释放锁之后,进行唤醒阻塞的状态的线程。
锁的状态暂时处于重量级锁状态。接下来会专门写一篇文章讲解一下锁降级哦,锁降级会较为复杂,而且场景完全不一样,对JVM要求也不一样。
当对象出现消亡了回收状态:
🏆【JVM技术专区】「难点-核心-遗漏」TLAB内存分配+锁的碰撞(技术串烧)!的更多相关文章
- ☕【Java技术指南】「难点-核心-遗漏」Java线程状态流转及生命周期的技术指南(知识点串烧)!
前提介绍 本章主要介绍相关线程声明周期的转换机制以及声明周期的流转关系以及相关AQS的实现和相关的基本原理,配合这相关官方文档的中英文互译的介绍. 线程状态流转及生命周期 当线程被创建并启动以后,它既 ...
- JVM基础学习(二):内存分配策略与垃圾收集技术
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来 垃圾收集概述 Java内存模型中的堆和方法区是垃圾收集技术所需要关注的终点,因为其他的区域会跟 ...
- JVM学习笔记-第三章-垃圾收集器与内存分配策略
JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...
- 【Java技术专题】「性能优化系列」针对Java对象压缩及序列化技术的探索之路
序列化和反序列化 序列化就是指把对象转换为字节码: 对象传递和保存时,保证对象的完整性和可传递性.把对象转换为有字节码,以便在网络上传输或保存在本地文件中: 反序列化就是指把字节码恢复为对象: 根据字 ...
- C++_类和动态内存分配6-复习各种技术及队列模拟
知识点: 队列:是一种抽象的数据类型(Abstract Data Type),可以存储有序的项目序列. 新项目被添加在队尾,并可以删除队首的项目.队列有些像栈.栈是在同一端进行添加和删除.这使得栈是一 ...
- LIbreOJ #6011. 「网络流 24 题」运输问题 最小费用最大流
#6011. 「网络流 24 题」运输问题 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- loj #547. 「LibreOJ β Round #7」匹配字符串
#547. 「LibreOJ β Round #7」匹配字符串 题目描述 对于一个 01 串(即由字符 0 和 1 组成的字符串)sss,我们称 sss 合法,当且仅当串 sss 的任意一个长度为 ...
- 一夜搞懂 | JVM GC&内存分配
前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习导图 一.为什么要学习GC&内存分配? 时代发展到现在,如今的内存动态分配与内存回收技术已经相当成 ...
- jvm系列 (二) ---垃圾收集器与内存分配策略
垃圾收集器与内存分配策略 前言:本文基于<深入java虚拟机>再加上个人的理解以及其他相关资料,对内容进行整理浓缩总结.本文中的图来自网络,感谢图的作者.如果有不正确的地方,欢迎指出. 目 ...
随机推荐
- 什么是EL表达式,以及作用
1.概念 EL(Expression Language) 是为了使JSP写起来更加简单.减少java代码,便于开发和维护. 2.语法 格式都是以"${}"表示. 3.与运算符 EL ...
- Drupal Drupalgeddon 2 远程代码执行漏洞(CVE-2018-7600)
影响版本 Drupal 6.x,7.x,8.x Drupal 是一款用量庞大的CMS,其6/7/8版本的Form API中存在一处远程代码执行漏洞 脚本检测
- Typora PicGo Gitee博客写作好搭档
利用Gitee仓库存放图片 1.首先在Gitee上创建一个公开的仓库,我这里创建了一个名叫resources的仓库: 2.在Gitee中获取私人令牌(个人设置界面中): 安装配置PicGo 1.下载自 ...
- sqli-labs 靶场笔记
sqli-labs 靶场笔记 冲冲冲,好好学习 2020年1月12号 先来点铺垫 分类: 按照请求方法分类: 1.Get型注入:注入参数在get的参数里. 2.POST型注入:注入参数在POST的参数 ...
- 在Java开发工具的project中使用相对路径
1.在project中,相对路径的根目录是project的根文件夹,在此就是repathtest文件夹了.创建文件的写法是: File f = new File("src/com/lavas ...
- centos7 安装mariadb、"systemctl status mariadb.service" and "journalctl -xe" for details
centos7 mariadb 安装 也可解决此错误:ob for mariadb.service failed because the control process exited with err ...
- SpringBoot @ModelAttribute 用法
前言 项目中遇到这么一个使用场景,用户的登录信息给予token保存,在需要有登录信息的地方,每次都要去获取用户Id,但每次在请求方法中去获取用户信息,代码重复,冗余,很low于是想到了用@ModelA ...
- Python中print()函数的用法
print()函数用于打印输出 1.函数语法: print(values,sep=' ',end='\n') sep和end是print()函数常用参数 参数sep是一次打印多个元素时的间隔符号,默认 ...
- 优秀Android开发简历都是这么写,你学会也可以进大厂
最近收了很多程序员的简历,工作经验从1年到十几年不等.发现一个问题,工作经验范围差不多的程序员,简历看起来也差不多... 为啥程序员的简历如此统一?正好最近看到一个分享也分析了这个问题,结合我个人的一 ...
- Rancher v1.6.29 Docker单节点部署
前言: Docker镜像中心,有两个版本的rancher(1.X),镜像名称为:rancher/server,而rancher(2.X)的镜像名称是rancher/rancher 去daocloud官 ...


