从头开始学习JVM(二)—— Java堆划分及对象的产生

本文详细介绍了JVM的Java堆内存结构,包括新生区、老年区的划分以及对象的产生过程。新生区分为伊甸区和幸存区,对象经历Minor GC后,根据年龄和内存状况进入老年区。对象的创建涉及堆内存分配,通过指针碰撞或空闲列表方式进行。此外,文章还探讨了线程安全的内存分配策略,如CAS操作和TLAB(本地线程分配缓冲)。
摘要由CSDN通过智能技术生成

JVM(Java Virtual Machine)即Java虚拟机,Java代码都是在JVM上运行的,所以了解JVM是成为Java高手的毕竟之路。

本系列内容将对JVM的知识进行介绍,是从头学习JVM知识的笔记。

本系列内容根据自己的学习和理解的基础上,并参考《深入理解Java虚拟机》一书介绍的知识所写。如果有写的不对的地方,请各位多多提点。



Java堆的划分

一个JVM中只有一个堆内存,其大小是可以调节的。所有的对象实例以及数组都要在堆上分配,所以堆唯一的目的就是存放对象的实例。

早期的堆内存可细分为三个部分:新生区(Young)、老年区(Old)、永久区 (PermGen space)。

JDK6之前堆中存在永久区;
JDK7开始“去永久代”,移除了永久区;
JDK8元数据空间(metaspace)取代了永久区,且元空间存在了本地内存中,即堆中只有新生区与老年区了。

Java堆结构

新生区(Young)

新生区又分为伊甸区(Eden)与幸存区(Survivor)。默认情况下年轻代按照8:1:1的比例(SurvivorRadio=8)来分配,可用参数 -XX:SurvivorRadio设置。

  • 伊甸区(Eden)

大多数情况下,对象在新生区中的伊甸区中分配。当伊甸区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。

大对象直接进入老年区。所谓的大对象是指需要大量连续内存的Java对象,最经典的大对象就是那种很长的字符串以及数组,伊甸区内存不足够存放的对象。

  • 幸存区(Survivor)

当经过Minor GC活下来的对象,将进入幸存区。幸存区分为from 和 to 两个区,这两个区是动态的,from 会动态的转换为 to。

幸存区一般使用的是复制算法(后面的GC算法中会讲到)。两个幸存区的作用在于提高性能,避免内存碎片的出现,但是牺牲了内存空间。在任何时候,总会有一个内存区是空的,在发生Minor GC后,对象会移到的幸存区就称为 from 区,to 区总是空的。而下一次Minor GC发生时,新对象和之前 from 区已存在的对象都放入 to 区中,此时 to 就动态变成了 from。

虚拟机中默认定义(MaxTenuringThreshold=15),在幸存区经过15次Minor GC的对象就会移到老年区。

老年区(Old)

老年区一般用于存放长生命周期的对象,通常是从幸存区中拷贝过来的对象。不过大对象是会直接进入老年区的。所谓的大对象是指需要大量连续内存的Java对象,最经典的大对象就是那种很长的字符串以及数组,伊甸区内存不足够存放的对象。

大对象对于虚拟机的内存分配来说是一个“坏消息”,特别是要避免出现一群“朝生夕灭”的“短命大对象”,短命大对象是灾难。经常出现大对象容易导致为了获取足够的连续空间,内存还有不少空间时就提前触发垃圾收集器收集它们。

虚拟机提供一个 -XX:PretenureSizeThreshold参数,当对象空间大于这个设置值时直接在老年区分配,这个参数是为了避免在Eden区和两个Survivor区之间发生大量的内存复制(幸存区使用的复制算法收集内存)。

对象年龄动态判定

为了更好的适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄(即经历的Minor GC次数)必须达到参数MaxTenuringThreshold规定的次数后才能晋升到老年区。如果在幸存区中相同年龄的所有对象的大小总和大于幸存区的一半,那么幸存区中年龄大于等于该对象指对象的大小总和大于幸存区的一半内存的这个“同龄对象”的年龄的就会进入老年代


对象的产生


对象的创建

此处的对象限于普通对象,不包括数组和Class对象等。

Java中,一个对象的创建往往是从new关键字开始,然后再经过init之后才能真正意义上的创建一个Java程序视角可用的对象实例。而Java中,也存在着许多使用new过程的操作,例如克隆、反序列化。


对象首次创建的过程

  • 当一个类被创建(A a=new A();),并且这个类是首次被加载时(去常量池定位到一个符号引用,且检查该引用代表的类没有被加载、解析和初始化过),将Class文件常量池中的变量装入运行时常量池,执行相应的类加载过程,会在堆中开辟出一块内存存放类的class文件(类对象模板)。
  • 然后在栈里申请空间,声明变量。接着会在堆中分配一块内存,存储这个类的实例。
  • 分配内存之后,将这个类的非静态的成员变量拷贝过来(静态成员不拷贝,所有实例共享)给变量分配内存,会把对象中的值都设为零值,并持有对应的方法区的方法的句柄。
  • 然后进行一些必要的设置(例如从对象头中读取类信息,锁状态等)。
  • 之后进行类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值