【10】对象一定在堆上分配吗

文章探讨了Java对象分配的特殊情形,包括直接内存用于提高数据传输效率,逃逸分析用于优化对象分配,以及TLAB(ThreadLocalAllocationBuffer)如何提升多线程分配性能。直接内存不受GC直接影响,逃逸分析可减少堆上分配,TLAB则为每个线程提供内存缓冲区以减少分配竞争。
摘要由CSDN通过智能技术生成

前言

一般认为,Java对象都是在堆上分配的,但也有一些特殊情况。比如NIO的直接内存,逃逸分析和TLAB,接下来详细解释下这三种。

直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域。

当数据需要通过网络发送到远程服务器时,使用堆内存需要进行额外的复制步骤,因为受GC影响堆内存地址会变化,所以需要一个固定的内存地址。首先,数据从堆内存复制到直接内存(堆外内存),然后再从直接内存发送到远程服务器。这个过程涉及了两次内存复制操作,可能会引入一些额外的开销和延迟。

而使用堆外内存,则可以省略掉这个额外的复制步骤。数据可以直接从堆外内存发送到远程服务器,避免了中间的复制操作,从而提高了数据传输的速度和效率。但是这部分内存被频繁地使用,可能导致OutOfMemoryError 异常出现,堆外内存难以控制,如果内存泄漏,那么很难排查。

直接内存不受 GC(新生代的 Minor GC) 影响,只有当执行老年代的 Full GC 时候才会顺便回收直接内存。

可以用DirectByteBuffer操作直接内存:

public static void main(String[] args) {
  
   // public static ByteBuffer allocateDirect(int capacity) {
   //     return new DirectByteBuffer(capacity);
   //}
   // 分配直接内存,大小为1MB
   ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024 * 1024);

   // 写入数据到直接内存
   String data = "Hello, Direct Memory!";
   directBuffer.put(data.getBytes());

   // 从直接内存读取数据
   directBuffer.flip();
   byte[] buffer = new byte[directBuffer.limit()];
   directBuffer.get(buffer);

   System.out.println(new String(buffer));

   // 释放直接内存
   directBuffer.clear();
}

逃逸分析

逃逸分析是Java虚拟机进行优化的一项技术,它可以分析方法中的对象引用,判断这些引用是否仅在方法内使用,从而决定是否将这些对象分配在堆上,可以把他理解为堆逃逸

如果一个对象的引用在方法内使用,并不会被传递到方法之外,可以被优化为栈上分配或标量替换等方式,这样该对象所占用的内存空间就可以随方法栈帧出栈而销毁,就减轻了垃圾回收的压力。相反,如果对象的引用将会被传递到方法之外,例如作为另一个对象的属性或返回给调用方法的方法外部,那么就必须将这个对象分配在堆上,以便其他线程也能够访问这个对象。

逃逸分析技术可以减少Java虚拟机在堆上分配对象的数量,从而减轻垃圾回收器的压力,提高程序的性能。

以下例子分析逃逸的可能性:

public user test1(){
   User user = new OrderService();
    // 对象的引用被传递到方法外了,不符合堆逃逸分析,分配到堆上
   return user;
}
public void test1(){
    // 对象的引用只在方法内部,符合了堆的逃逸分析,可以分配到栈上。
   User user = new User();
  System.out.println(user);
}

标量替换:通过逃逸分析确定该对象不会被外部访问,将该对象成员变量分解若干个被这个方法使用的成员变量所代替,这样就不会因为没有一大块连续空间导致对象内存不够分配。

TLAB分配

其实TLAB是在堆内画了一块空间,新建对象分配到TLAB中,按道理来说新建的对象也分配到了堆中。

TLAB解释:

是Java虚拟机为每个线程分配的一块内存缓冲区,用于快速分配对象。TLAB通过为每个线程分配私有的内存缓冲区,使得每个线程都可以在自己的TLAB上分配对象,而无需竞争堆内存的分配指针。这样一来,多线程之间的分配操作可以并行进行,减少了竞争和同步的开销,提高了分配的性能。

通过XX:+UseTLAB参数来设定虚拟机是否使用TLAB(JVM会默认开启XX:+UseTLAB),­XX:TLABSize 指定TLAB大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值