点击上方“linkoffer”,

选择关注公众号高薪职位第一时间送达

作者 l Hollis

JVM内存结构,是很重要的知识,相信每一个静心准备过面试的程序员都可以清楚的把堆、栈、方法区等介绍的比较清楚。


上图,是一张在作者根据《Java虚拟机规范(Java SE 8)》中描述的JVM运行时内存区域结构画的。

很多人都知道Java对象是在堆内存中分配空间的(JIT优化除外),也知道内存分配过程中是线程安全的,那么虚拟机到底是如何保证线程安全的呢?本文就来简单介绍一下。

1

Java对象的内存分配

我们知道,Java是一门面向对象的语言,我们在Java中使用的对象都需要被创建出来,在Java中,创建一个对象的方法有很多种,如使用new、使用反射、使用Clone方法等,但是无论如何,对象在创建过程中,都需要进行内存分配。

拿最常见的new关键字举例,当我们使用new创建对象后代码开始运行后,虚拟机执行到这条new指令的时候,会先检查要new的对象对应的类是否已被加载,如果没有被加载则先进行类加载。

在类加载检查通过之后,就需要给对象进行内存分配了,分配的内存主要用来存放对象的实例变量。

在进行内存分配时,需要根据对象中的实例变量情况等信息确定需要分配的空间大小,然后从Java堆中划分出这样一块区域(假设没有JIT优化)。

根据JVM使用的垃圾回收器的类型,因其回收算法不同,会导致堆中内存分配情况不同。如标记-清楚算法回收后的内存中会有大量不连续的内存碎片,在给新的对象分配的时候,就需要通过"空闲列表"来确定一块空闲区域。(这部分不是本文重点,读者可以自行学习一下。)

无论那种方式,最终都需要确定出一块内存区域,用于给新建对象分配内存。我们知道,对象的内存分配过程中,主要是对象的引用指向这个内存区域,然后进行初始化操作。

那么问题就来了:

在并发场景中,如何内存分配过程的线程安全性?如果两个线程先后把对象引用指向了同一个内存区域,怎么办。

2

TLAB

一般有两种解决方案:

  • 1、对分配内存空间的动作做同步处理,采用CAS机制,配合失败重试的方式保证更新操作的线程安全性。

  • 2、每个线程在Java堆中预先分配一小块内存,然后再给对象分配内存的时候,直接在自己这块"私有"内存中分配,当这部分区域用完之后,再分配新的"私有"内存。

方案1在每次分配时都需要进行同步控制,这种是比较低效的。

方案2是HotSpot虚拟机中采用的,这种方案被称之为TLAB分配,即Thread Local Allocation Buffer。这部分Buffer是从堆中划分出来的,但是是本地线程独享的。

这里值得注意的是,我们说TLAB时线程独享的,但是只是在“分配”这个动作上是线程独占的,至于在读取、垃圾回收等动作上都是线程共享的。而且在使用上也没有什么区别。

另外,TLAB仅作用于新生代的Eden Space,对象被创建的时候首先放到这个区域,但是新生代分配不了内存的大对象会直接进入老年代。因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。

所以,虽然对象刚开始可能通过TLAB分配内存,存放在Eden区,但是还是会被垃圾回收或者被移到Survivor Space、Old Gen等。

不知道大家有没有想过,我们使用了TLAB之后,在TLAB上给对象分配内存时线程独享的了,这就没有冲突了,但是,TLAB这块内存自身从堆中划分出来的过程也可能存在内存安全问题啊。

所以,在对于TLAB的分配过程,还是需要进行同步控制的。但是这种开销相比于每次为单个对象划分内存时候对进行同步控制的要低的多。

虚拟机是否使用TLAB是可以选择的,可以通过设置-XX:+/-UseTLAB参数来指定。

3

总结

为了保证Java对象的内存分配的安全性,同时提升效率,每个线程在Java堆中可以预先分配一小块内存,这部分内存称之为TLAB(Thread Local Allocation Buffer),这块内存的分配时线程独占的,读取、使用、回收是线程共享的。

可以通过设置-XX:+/-UseTLAB参数来指定是否开启TLAB分配。

独占设备的分配与回收_灵魂拷问:Java对象的内存分配过程是如何保证线程安全的?...相关推荐

  1. 原创 | 灵魂拷问:Java对象的内存分配过程是如何保证线程安全的?

    △Hollis, 一个对Coding有着独特追求的人△ 这是Hollis的第 222 篇原创分享 作者 l Hollis 来源 l Hollis(ID:hollischuang) JVM内存结构,是很 ...

  2. java对象的内存分配流程

    了解对象的内存分配流程对常见内存溢出问题.jvm优化有很大作用. 内存分配原则 对象栈内分配 通常理解new对象都在堆中分配存储空间,但是当(通过逃逸分析 确定)对象仅在方法内使用而未被外部访问的时候 ...

  3. 源码分析:Java对象的内存分配

    Java对象的分配,根据其过程,将其分为快速分配和慢速分配两种形式,其中快速分配使用无锁的指针碰撞技术在新生代的Eden区上进行分配,而慢速分配根据堆的实现方式.GC的实现方式.代的实现方式不同而具有 ...

  4. 深入理解Java虚拟机(第三弹)- JVM 内存分配与回收策略原理,从此告别 JVM 内存分配文盲

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:打卡活动第二期来啦,100% 能获得奖品个人原创+1博客:点击前往,查看更多 虚拟机系列文章 深入理解 Java ...

  5. jvm学习笔记(3)——java对象的内存分配和对象的回收(GC)

    引言: 之前的文章已经提过,java对象实例是存放在堆上的,至于是在伊甸区.存活区还是老年区,这些都是从对象回收(GC)角度来进行的逻辑划分.所以我们先说对象的回收(GC),然后再依据GC的策略来说明 ...

  6. java对象的内存分配

    (1) 寄存器(register).这是最快的保存区域,这是主要由于它位于处理器内部.然而,寄存器的数量十分有限,所以寄存器是需要由编译器分配的.我们对此没有直接的控制权,也不可能在自己的程序里找到寄 ...

  7. java对象的内存分配_java对象在内存的分配问题

    今天看到一个不错的PPT:Build Memory-efficient Java Applications,开篇便提出了一个问题,在Hotspot JVM中,32位机器下,Integer对象的大小是i ...

  8. 秘境探索之一个.NET 对象从内存分配到内存回收

    前方高能预警,新手慎入!不听劝阻者,轻则郁闷堆积,重则生死看淡,对编程失去了念想,对生活失去了幻想!好了,心理强大到NB的可以忽略前方若干警示.为了探索.NET对象的内存分配和回收销毁,您可能需要准备 ...

  9. Java基础-Java中的内存分配与回收机制

    Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二. 转载于:https://www.cnblogs.com/yinzhengji ...

最新文章

  1. C++ 文件大小格式化
  2. Git - 使用指南
  3. oracle 11g 从rman全备中恢复控制文件,拥有RMAN全备(缺少后增文件),丢失全部数据文件,控制文件的恢复...
  4. const char *p,char const *p, char * const p之间的区别
  5. android 圆环温度控件,android 圆环倒计时控件
  6. 大数据之Yarn——Capacity调度器概念以及配置
  7. java之NIO(Channel,Buffer,Selector)
  8. php框架laravel_Laravel简介(PHP框架)
  9. leetcode 三数之和 python_16.leetcode题目讲解(Python):最接近的三数之和
  10. 重构-改善既有的代码设计-------代码的坏味道
  11. 职业生涯第一次:老板让我写个 BUG!
  12. DDNS-动态域名解析服务
  13. mybatis防止sql注入
  14. tomcat查看当前内存
  15. linux第五单元作业,第五单元《微型计算机系统》教案
  16. java前端开发_Java前端开发学习什么内容
  17. 前端和后端的英文_前端开发与架构师
  18. bugzilla使用规范分享
  19. StringBuilder的介绍(转载!)
  20. 身份证号提取年龄方法python_身的解释|身的意思|汉典“身”字的基本解释

热门文章

  1. 领域驱动设计,让程序员心中有码
  2. 广州 office365的开发者训练营交流活动简报
  3. 开源个.NetCore写的 - 并发请求工具PressureTool
  4. asp.net core 认证及简单集群
  5. 中间件和微服务,Docker以及原生云架构的关系
  6. 汉诺塔c语言源程序步骤,汉诺塔问题的算法分析及C语言演示程序的实现
  7. Win11 的日历 替代
  8. C语言,C#语言求100-999内的水仙花数源程序
  9. C语言试题八十五之狼追兔子问题
  10. Git之提示There is no tracking information for the current branch.