假设这将在一个真正的并行环境中同时在一个VM上发生:
// Thread 1:
new Cat()
// Thread 2:
new Dog()
// Thread 3:
new Mouse()
JVM如何确保堆上内存分配的线程安全性?
堆是所有线程的一个,它有自己的内部数据。
为简单起见,假设一个简单的压缩垃圾收集器实现-XX:+ UseSerialGC -XX:+
UseParallelGC,带有简单的增量指针,用于标记Eden(堆)中的可用空间的开始和一个连续的可用空间。
当为 Cat , Dog 和 Mouse 实例分配堆空间时,线程之间必须存在某种同步,否则它们最终很容易彼此覆盖。这是否意味着每个 新
运算符都隐藏在某些同步块中?这样,许多“无锁”算法实际上并不是完全无锁的;)
我假定内存分配是由应用程序线程本身同步进行的,而不是由另一个专用线程进行的。
我知道TLAB或线程本地分配缓冲区。它们允许线程在Eden中具有单独的内存区域以进行分配,因此不需要同步。但是我不确定是否默认设置了TLAB,它在某种程度上是非常模糊的HotSpot功能。注意:请勿混淆TLAB和ThreadLocal
变量!
我还假设,对于更复杂的垃圾收集器(例如G1)或非紧凑型垃圾收集器,必须维护更复杂的堆结构数据,例如CMS的可用块列表,因此需要更多的同步。
更新 :请让我澄清一下。对于有和没有活动TLAB的HotSpot JVM实现及其变体,我都接受答案。
更新 :根据我的快速测试,
默认情况下 ,在我的64位JDK 7上,串行,并行和CMS垃圾收集器的 TLAB设置为ON ,但对于G1 GC则没有。
TLAB是伊甸园中保留给线程本地分配的区域。每个线程可以创建许多TLAB:一旦一个线程被填充,就会使用#2中描述的技术创建一个新的TLAB。即,创建新的TLAB就像在Eden中直接分配大型元对象。
每个Java线程都有两个指针:tlab_top
和tlab_limit
。TLAB中的分配只是指针增量。由于指针是线程本地的,因此不需要同步。
if (tlab_top + object_size <= tlab_limit) {
new_object_address = tlab_top;
tlab_top += object_size;
}
-XX:+UseTLAB
默认情况下启用。如果将其关闭,则对象将在Eden中分配,如下所述。
如果TLAB中没有足够的空间用于新对象,则创建新的TLAB或直接在Eden中分配对象(取决于TLAB废物限制和其他人体工程学参数)。
在Eden中的分配类似于在TLAB中的分配。还有两个指针:eden_top
和eden_end
,它们对于整个JVM是全局的。分配也是指针增量,但是由于所有线程之间都共享Eden空间,因此使用原子操作。通过使用特定于体系结构的原子指令来实现线程安全:CAS(例如,LOCK CMPXCHG
在x86上)或LL / SC(在ARM上)。
这取决于GC算法,例如CMS使用空闲列表。老一代中的分配通常仅由垃圾收集器本身执行,因此它知道如何同步自己的线程(通常与分配缓冲区,无锁原子操作和互斥锁的混合)。
我在理解JVM进程如何分配自己的内存方面有一点差距。据我所知 其中堆外由线程堆栈、直接缓冲区、映射文件(库和JAR)和JVM代码本身组成; 目前,我正在尝试分析我的Java应用程序(Spring Boot Infinispan),RSS779M(它在docker容器中运行,所以pid 1是可以的): 换句话说,我想解释799M-(374M 89M)=316M堆外内存。 这些线程中的每一个都消耗1M
问题内容: 我正在编写一个需要处理内存中私钥的快速应用程序。由于此类对象的敏感性,因此在释放对象时需要清除键(也就是将其写为全零),并且无法将内存分页到磁盘(通常使用mlock()完成)。 在Objective-C中,您可以提供一个自定义CFAllocator对象,该对象允许您使用自己的函数来分配/取消分配/重新分配对象使用的内存。 因此,一种解决方案是仅在Objective-C中实现一个“ Se
本文向大家介绍如何保证线程安全?相关面试题,主要包含被问及如何保证线程安全?时的应答技巧和注意事项,需要的朋友参考一下 考察点:线程 通过合理的时间调度,避开共享资源的存取冲突。另外,在并行任务设计上可以通过适当的策略,保证任务与任务之间不存在共享资源,设计一个规则来保证一个客户的计算工作和数据访问只会被一个线程或一台工作机完成,而不是把一个客户的计算工作分配给多个线程去完成。
问题内容: 假设我们的应用程序中有一个CountryList对象,该对象应返回国家/地区列表。国家/地区的加载是一项繁重的操作,因此应将列表缓存。 其他要求: CountryList应该是线程安全的 CountryList应该延迟加载(仅按需加载) CountryList应该支持缓存无效 考虑到极少数情况下会使缓存无效,应该优化CountryList 我想出了以下解决方案: 你怎么看待这件事?你看
问题内容: 是否可以通过任何常规方法或规则来确保专门用于任何应用程序的各种Utility类的静态方法的线程安全性。在这里,我想特别指出Web应用程序的线程安全性。 众所周知,以不可变对象作为参数的静态方法是线程安全的,而可变对象不是。 如果我有一个实用程序方法可用于的某些操作,并且该方法接受的实例,则该方法将不是线程安全的。那么如何在不更改参数传递方式的情况下使其成为线程安全的呢? 课堂也是可变的
问题内容: Spring对象是线程安全的吗?如果没有,如何使它们线程安全? 问题答案: 这是两个不相关的问题: spring线程安全吗? 没有。 Spring具有不同的bean 作用域(例如Prototype,Singleton等),但是所有这些作用域都是在创建bean 时强制执行的。例如,每次“注入”一个“原型”范围的bean都会被创建,而一个“单个”范围的bean将被创建一次并在应用程序上下文