java System.arraycopy() 对应Hotspot里面的源码

本文详细解析了Java中System.arraycopy()方法在HotSpot虚拟机中的源码实现,涉及JNI调用、内存地址操作和不同数据类型数组的原子性复制过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java System.arraycopy() 对应Hotspot里面的源码

public class Copy {
    public static void main(String[] args) throws InterruptedException {
        String x = "123456789";
        System.out.println("start");
        Thread.sleep(3000);
        byte[] bytes1 = x.getBytes();
        byte[] bytes = new byte[32];
        System.arraycopy(bytes1, 0, bytes, 0, 8);//本质是将一个内存地址的值复制到另一个内存地址

    }
}
// System.arraycopy 本地方法
 @HotSpotIntrinsicCandidate
    public static native void arraycopy(Object var0, int var1, Object var2, int var3, int var4);

jvm.cpp 307行为本地方法入口


JVM_ENTRY(void, JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos,
                               jobject dst, jint dst_pos, jint length))
  JVMWrapper("JVM_ArrayCopy");
  // Check if we have null pointers
  if (src == NULL || dst == NULL) {
    THROW(vmSymbols::java_lang_NullPointerException());
  }
  arrayOop s = arrayOop(JNIHandles::resolve_non_null(src));
  arrayOop d = arrayOop(JNIHandles::resolve_non_null(dst));
  assert(s->is_oop(), "JVM_ArrayCopy: src not an oop");
  assert(d->is_oop(), "JVM_ArrayCopy: dst not an oop");
  // Do copy
  s->klass()->copy_array(s, src_pos, d, dst_pos, length, thread);
JVM_END
//进入klass()->copy_array(s, src_pos, d, dst_pos, length, thread);  
void TypeArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS) {
//省略了其他检查逻辑
  int l2es = log2_element_size();
  int ihs = array_header_in_bytes() / wordSize;
  char* src = (char*) ((oop*)s + ihs) + ((size_t)src_pos << l2es);
  char* dst = (char*) ((oop*)d + ihs) + ((size_t)dst_pos << l2es);
  Copy::conjoint_memory_atomic(src, dst, (size_t)length << l2es);
}

下面断点截图同src 地址为 0xff0bd920 值为123456789 确实和java代码里的值一样
dst代表目标地址 地址为 0xff0bd940
在这里插入图片描述

继续进入函数

// Copy bytes; larger units are filled atomically if everything is aligned.
void Copy::conjoint_memory_atomic(void* from, void* to, size_t size) {
  address src = (address) from;
  address dst = (address) to;
  uintptr_t bits = (uintptr_t) src | (uintptr_t) dst | (uintptr_t) size;
//将 要复制数组的内存地址 和目的地址已经长度 进行或运算  在下面根据结果判断 是否是对齐的 8字节对齐 4字节对齐和2直接对齐 这里我刻意拷贝8个字节代码进入第一个分支
  if (bits % sizeof(jlong) == 0) {
    Copy::conjoint_jlongs_atomic((jlong*) src, (jlong*) dst, size / sizeof(jlong));
  } else if (bits % sizeof(jint) == 0) {
    Copy::conjoint_jints_atomic((jint*) src, (jint*) dst, size / sizeof(jint));
  } else if (bits % sizeof(jshort) == 0) {
    Copy::conjoint_jshorts_atomic((jshort*) src, (jshort*) dst, size / sizeof(jshort));
  } else {
    // Not aligned, so no need to be atomic.
    Copy::conjoint_jbytes((void*) src, (void*) dst, size);
  }
}

  // bytes, jshorts, jints, jlongs, oops

  // bytes,                 conjoint, not atomic on each byte (not that it matters)
  static void conjoint_jbytes(void* from, void* to, size_t count) {
    pd_conjoint_bytes(from, to, count);
  }

static void pd_conjoint_jlongs_atomic(jlong* from, jlong* to, size_t count) {
#ifdef AMD64
  _Copy_conjoint_jlongs_atomic(from, to, count);

接着进入

在这里插入图片描述

执行到jbe 0x9e6fa6会进入真正的拷贝逻辑 (注意此时 rax寄存器和rdi 寄存器里面保存的 要复制的内存地址的值)
下面是真正的复制逻辑 此时rsi寄存器的值还为改变 当执行完 movq 0x8(%rax,%rdx,8), %rsi 高亮的代码后rsi里面回存放要复制的值(12345678)刚好为8个字节
在这里插入图片描述
执行结果 rsi 已经为要复制的值 0x3837363534333231 这里为什么不是12345678呢 因为 12345678的asc编码就是3132333435363738

movq %rsi,0x8(%rcx,%rdx,0) 的意思是将rsi寄存器里面的值给到 目标的内存地址 也就是 0xff0bd940 (从下方的调试窗口给出的寄存器值手动计算也是这个值)
在这里插入图片描述
这里我们输出一下 0xff0bd940 的值

在这里插入图片描述

您好!以下是JavaSystem类中arraycopy方法的简化版源码: ```java public class System { public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { // 源数组和目标数组必须是对象数组 if (!(src instanceof Object[] && dest instanceof Object[])) { throw new ArrayStoreException("Source and destination arrays must be of the same type"); } // 检查数组范围 if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > ((Object[]) src).length || destPos + length > ((Object[]) dest).length) { throw new IndexOutOfBoundsException(); } // 执行数组复制 if (src != dest) { if (srcPos < destPos) { // 从后往前复制 for (int i = length - 1; i >= 0; i--) { ((Object[]) dest)[destPos + i] = ((Object[]) src)[srcPos + i]; } } else { // 从前往后复制 for (int i = 0; i < length; i++) { ((Object[]) dest)[destPos + i] = ((Object[]) src)[srcPos + i]; } } } } } ``` 上述源码展示了System类的arraycopy方法的实现。该方法用于将源数组中的元素复制到目标数组中。在执行复制前,该方法会进行数组类型的检查和范围的检查。如果源数组和目标数组不是对象数组,将抛出ArrayStoreException异常。如果索引位置或长度超出数组的范围,将抛出IndexOutOfBoundsException异常。最后,根据源数组和目标数组的位置关系,使用循环逐个复制元素到目标数组。 请注意,这只是arraycopy方法的简化版源码,实际源码可能会更复杂并涉及一些优化。此外,该源码可能与特定的Java版本有所不同,以上代码仅供参考。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值