内存区域组成
包括:
{堆、方法区}所有线程共享数据区。在JDK8中,hotspot宣布移除PermGen内存区域,以“元数据区”(Metaspace)替代之。
{虚拟机栈、本地方法栈、程序计数器}线程隔离数据区
{直接内存NIO} 基于通道与缓冲区的I/O方式,使用native方法分配堆外内存。若各块内存和大于可分配内存,则报OutOfMemortyError
对象在JVM上创建的过程
1.检查new指令参数能否在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否被加载、解析、初始化过。如果没有,则进行类的加载。加载完成后,可获得对象所需的内存大小。
2.虚拟机为新生的对象分配内存。内存规整(指针碰撞),内存不规整(空闲列表)。
垃圾收集器是否带有压缩整理功能,决定了内存是否规整。
Serail,ParNew等带compact过程的收集器,采用的是指针碰撞
CMS等基于Mark-Swap算法的收集器,采用的是空闲列表
3.解决高并发下,指针修改问题。
CAS配上重试失败方法
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该 位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前 值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”
通常将 CAS 用于同步的方式是从地址 V 读取值 A,执行多步计算来获得新 值 B,然后使用 CAS 将 V 的值从 A 改为 B。如果 V 处的值尚未同时更改,则 CAS 操作成功。
类似于 CAS 的指令允许算法执行读-修改-写操作,而无需害怕其他线程同时 修改变量,因为如果其他线程修改变量,那么 CAS 会检测它(并失败),算法 可以对该操作重新计算。
本地线程分配缓存
将内存分配的动作按照线程划分在不同的空间中进行,即每个线程在JAVA堆中预先分配一小块内存。当TLAB并分配新的TLAB时,才需要同步锁定
4.虚拟机将对象分配到的空间,初始化为0值。
5.对象初始化。
对象的内存布局
包括:
对象头
实例数据
对齐填充
对象的访问定位
通过栈上的reference来进行访问
包括:
句柄访问,优点:对象被移动时,只会修改实例数据指针
直接地址访问,优点:速度快,节省一次指针查找的开销。
网友评论