JVM自动内存管理

Java虚拟机的内存管理是Java语言能够稳定、高效运行的基础。在JVM中,内存区域被划分为几个不同的部分,它们各有特点并扮演着不同的角色。

1. 线程共享区域与线程独享区域
在JVM中,内存区域可以分为两类:线程共享区域和线程独享区域。

线程共享区域包括:

方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
堆(Heap): 用于存储对象实例,是GC管理的主要区域。堆可以细分为新生代和老年代。
线程独享区域包括:

虚拟机栈(VM Stack): 每个线程都有一个私有的虚拟机栈,它的生命周期与线程相同。这个区域主要用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
本地方法栈(Native Method Stack): 与虚拟机栈类似,为虚拟机使用到的Native方法服务。
程序计数器(Program Counter Register): 是线程私有的,每个线程都有一个程序计数器,用于记录正在执行的虚拟机字节码指令的地址。
2. 堆内存管理
堆内存是Java虚拟机中最大的一块内存区域,主要用于存储对象实例。当创建一个对象时,JVM会在堆内存中为其分配空间。

为了更好地管理堆内存,JVM将堆内存划分为了两大部分:新生代和老年代。

新生代:存放新创建的对象,大部分对象在这里诞生、生存和消亡。当对象经历了多次垃圾回收仍然存活时,就会被晋升到老年代。
老年代:存放从新生代晋升的对象,以及一些大对象。老年代的内存回收频率相对较低。
为了更好地利用堆内存,JVM采用了复制算法和标记-整理算法进行垃圾回收。此外,还引入了TLAB(Thread Local Allocation Buffer)技术,以降低并发访问堆内存的开销。

3. 方法区内存管理
方法区是JVM的内存空间之一,用于存储已被虚拟机加载的类信息、常量、静态变量等数据。与堆内存类似,方法区的内存也会随着类的加载而不断增大,因此也需要进行垃圾回收。

不同于堆内存使用分代收集的策略,方法区采用的是标记-清除算法进行垃圾回收。在进行垃圾回收时,会标记出需要回收的类信息,然后进行清除操作。

值得注意的是,在JDK 8及之后的版本中,方法区被移除,取而代之的是元空间(Metaspace)。元空间使用的是本地内存,不再受限于物理内存的大小。

4. 对象的创建过程
当我们在Java程序中创建一个新对象时,JVM会执行以下步骤:

类加载检查: 首先检查该类是否已经被加载、解析和初始化。如果没有,则执行相应的类加载过程。
内存分配: 在堆内存中为对象分配空间。如果使用的是指针碰撞算法,则直接在Java堆中分配;如果使用的是空闲列表算法,则需要在空闲列表中找到一块足够大的空间进行分配。
内存初始化: 为对象的实例变量赋予初始值。
对象头设置: 设置对象的对象头,包括自身的Class指针、哈希码、GC分代年龄等信息。
执行 <init> 方法: 执行构造函数,初始化对象。
在这个过程中,JVM还会利用TLAB(Thread Local Allocation Buffer)技术来优化内存分配,提高并发性能。

5. 对象的访问定位
在JVM中,有两种方式来访问堆中的对象:

句柄访问: 在堆中分配一块独立的内存空间作为句柡,ref中存储的就是指向这个句柄的指针。使用句柄的最大好处就是 reference 中存储的是稳定的句柄地址,即使对象被移动(垃圾收集时移动对象)时,也不会影响访问的定位。
直接指针访问: ref中存储的直接就是对象地址。这种方式的最大好处就是速度更快,节省了一次指针定位的时间开销。
两种方式各有优缺点,具体使用哪种方式由JVM自行决定,这对用户来说是透明的。

总的来说,JVM的自动内存管理为Java程序的稳定、高效运行提供了坚实的基础。通过合理划分内存区域、采用高效的垃圾回收算法,JVM能够有效管理和利用有限的内存资源,大大提高了Java程序的性能和可靠性。

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值