JVM内存结构,是很重要的知识,相信每一个静心准备过面试的程序员都可以清楚的把堆、栈、方法区等介绍的比较清楚。  上图,是一张在作者根据《Java虚拟机规范(Java SE 8)》中描述的JVM运行时内存区域结构画的。再强调一下,以上是JVM规范定义的逻辑分区,不同的虚拟机厂商,或者相同的虚拟机的不同版本实现上也不尽相同。 很多人都知道Java对象是在堆内存中分配空间的(JIT优化除外),也知道内存分配过程中是线程安全的,那么虚拟机到底是如何保证线程安全的呢?本文就来简单介绍一下。 Java对象的内存分配我们知道,Java是一门面向对象的语言,我们在Java中使用的对象都需要被创建出来,在Java中,创建一个对象的方法有很多种,如使用new、使用反射、使用Clone方法等,但是无论如何,对象在创建过程中,都需要进行内存分配。 拿最常见的new关键字举例,当我们使用new创建对象后代码开始运行后,虚拟机执行到这条new指令的时候,会先检查要new的对象对应的类是否已被加载,如果没有被加载则先进行类加载。 在类加载检查通过之后,就需要给对象进行内存分配了,分配的内存主要用来存放对象的实例变量。 在进行内存分配时,需要根据对象中的实例变量情况等信息确定需要分配的空间大小,然后从Java堆中划分出这样一块区域(假设没有JIT优化)。 根据JVM使用的垃圾回收器的类型,因其回收算法不同,会导致堆中内存分配情况不同。如标记-清楚算法回收后的内存中会有大量不连续的内存碎片,在给新的对象分配的时候,就需要通过"空闲列表"来确定一块空闲区域。(这部分不是本文重点,读者可以自行学习一下。) 无论那种方式,最终都需要确定出一块内存区域,用于给新建对象分配内存。我们知道,对象的内存分配过程中,主要是对象的引用指向这个内存区域,然后进行初始化操作。 那么问题就来了: 在并发场景中,如何内存分配过程的线程安全性?如果两个线程先后把对象引用指向了同一个内存区域,怎么办。 TLAB 一般有两种解决方案:
方案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参数来指定。 TLAB 为了保证Java对象的内存分配的安全性,同时提升效率,每个线程在Java堆中可以预先分配一小块内存,这部分内存称之为TLAB(Thread Local Allocation Buffer),这块内存的分配时线程独占的,读取、使用、回收是线程共享的。 可以通过设置-XX:+/-UseTLAB参数来指定是否开启TLAB分配。
|
java 线程安全的 内存轮询 java线程内存分配
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
深入浅出Java多线程(六):Java内存模型
大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第六篇内容:Java内存模型。大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!!
Java Java多线程 Java内存模型 JVM 多线程 -
java 线程安全的int
java 线程安全的int
线程安全 原子变量 Java -
java 内存 控制 线程 java线程内存分配
java中内存的分配 java程序在运行时,内存结构分为:方法区(method),栈内存(stack),堆内存(heap),本地方法栈(java中的jni调用)等。
java 内存 控制 线程 java中内存的分配 bc 方法区 数据 -
java 线程分配的空间 java线程内存分配
一、JVM内存 1.线程共享内存 ① Java堆区:用于存储对象实例 ② 方法区:存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
java 线程分配的空间 内存分配 逃逸分析 私有内存 共享内存 -
Java内存太小线程分配 java 线程工作内存
JVM将内存组织为主内存和工作内存两个部分。 主内存是所有的线程所共享的,主要包括本地方法区和堆。 每个线程都有一个工作内存不是共享的,工作内存中主要包括两个部分:
Java内存太小线程分配 jvm java 执行引擎 赋值