System.arraycopy 本地方法 源代码分析
来源:互联网 发布:淘宝积分换购物券 编辑:程序博客网 时间:2024/06/14 07:37
文章中源代码版本
JDK:jdk1.8.0_11
OpenJDK:openjdk-8u40-src-b25-10_feb_2015 【给出下载链接:openjdk8】
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
Java中的一个数组拷贝内容到另一个数组经常使用System.arraycopy()方法,但是查看源代码可以发现该方法声明为native,也就是说是本地方法,不是用Java写的。Java可以通过JNI来调用其他语言(主要还是C/C++语言)编写的方法。本文中就通过查看OpenJDK中的源码,简单分析一下System.arraycopy()方法的实现。如有不正确的地方,望指正!
1、打开openjdk\hotspot\src\share\vm\prims\jvm.cpp可以看到一个方法JVM_ArrayCopy,但是该方法没有真正实现复制的代码,而是简单的检测源数组和目的数组不为空,排除一些异常情况
/*java.lang.System中的arraycopy方法*/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
2、openjdk\hotspot\src\share\vm\oops\objArrayKlass.cpp文件中copy_array方法
/*java.lang.System中的arraycopy方法具体实现*/void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS) { //检测s是数组 assert(s->is_objArray(), "must be obj array"); //目的数组不是数组对象的话,则抛出ArrayStoreException异常 if (!d->is_objArray()) { THROW(vmSymbols::java_lang_ArrayStoreException()); } // Check is all offsets and lengths are non negative //检测下标参数非负 if (src_pos < 0 || dst_pos < 0 || length < 0) { THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); } // Check if the ranges are valid //检测下标参数是否越界 if ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) ) { THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); } // Special case. Boundary cases must be checked first // This allows the following call: copy_array(s, s.length(), d.length(), 0). // This is correct, since the position is supposed to be an 'in between point', i.e., s.length(), // points to the right of the last element. //length==0则不需要复制 if (length==0) { return; } //UseCompressedOops只是用来区分narrowOop和oop,具体2者有啥区别需要再研究 //调用do_copy函数来复制 if (UseCompressedOops) { narrowOop* const src = objArrayOop(s)->obj_at_addr<narrowOop>(src_pos); narrowOop* const dst = objArrayOop(d)->obj_at_addr<narrowOop>(dst_pos); do_copy<narrowOop>(s, src, d, dst, length, CHECK); } else { oop* const src = objArrayOop(s)->obj_at_addr<oop>(src_pos); oop* const dst = objArrayOop(d)->obj_at_addr<oop>(dst_pos); do_copy<oop> (s, src, d, dst, length, CHECK); }}
do_copy方法
// Either oop or narrowOop depending on UseCompressedOops.template <class T> void ObjArrayKlass::do_copy(arrayOop s, T* src, arrayOop d, T* dst, int length, TRAPS) { BarrierSet* bs = Universe::heap()->barrier_set(); // For performance reasons, we assume we are that the write barrier we // are using has optimized modes for arrays of references. At least one // of the asserts below will fail if this is not the case. assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt"); assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well."); if (s == d) { // since source and destination are equal we do not need conversion checks. assert(length > 0, "sanity check"); bs->write_ref_array_pre(dst, length);//复制的函数 Copy::conjoint_oops_atomic(src, dst, length); } else { // We have to make sure all elements conform to the destination array Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass(); Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass(); if (stype == bound || stype->is_subtype_of(bound)) { // elements are guaranteed to be subtypes, so no check necessary //stype对象是bound,或者stype是bound的子类抑或stype实现bound接口 bs->write_ref_array_pre(dst, length); Copy::conjoint_oops_atomic(src, dst, length); } else { // slow case: need individual subtype checks // note: don't use obj_at_put below because it includes a redundant store check T* from = src; T* end = from + length; for (T* p = dst; from < end; from++, p++) { // XXX this is going to be slow. T element = *from; // even slower now bool element_is_null = oopDesc::is_null(element); oop new_val = element_is_null ? oop(NULL) : oopDesc::decode_heap_oop_not_null(element); if (element_is_null || (new_val->klass())->is_subtype_of(bound)) { bs->write_ref_field_pre(p, new_val); *p = element; } else { // We must do a barrier to cover the partial copy. const size_t pd = pointer_delta(p, dst, (size_t)heapOopSize); // pointer delta is scaled to number of elements (length field in // objArrayOop) which we assume is 32 bit. assert(pd == (size_t)(int)pd, "length field overflow"); bs->write_ref_array((HeapWord*)dst, pd); THROW(vmSymbols::java_lang_ArrayStoreException()); return; } } } } bs->write_ref_array((HeapWord*)dst, length);}
3、在openjdk\hotspot\src\share\vm\utilities\copy.hpp文件中找到该conjoint_oops_atomic函数,还有针对narrowOop的重载函数,这里不写出
// oops, conjoint, atomic on each oop static void conjoint_oops_atomic(oop* from, oop* to, size_t count) { assert_params_ok(from, to, LogBytesPerHeapOop); pd_conjoint_oops_atomic(from, to, count); }
4、openjdk\hotspot\src\share\vm\oops\klass.hpp中的is_subtype_of函数
//检测是否是k的子类,或者是实现k接口 bool is_subtype_of(Klass* k) const { juint off = k->super_check_offset(); Klass* sup = *(Klass**)( (address)this + off ); const juint secondary_offset = in_bytes(secondary_super_cache_offset()); if (sup == k) { return true; } else if (off != secondary_offset) { return false; } else { return search_secondary_supers(k); } }
5、openjdk\hotspot\src\os_cpu\windows_x86\vm\copy_windows_x86.inline.hpp,最主要就是pd_conjoint_oops_atomic函数
static void pd_conjoint_oops_atomic(oop* from, oop* to, size_t count) { // Do better than this: inline memmove body NEEDS CLEANUP if (from > to) { while (count-- > 0) { // Copy forwards *to++ = *from++; } } else { from += count - 1; to += count - 1; while (count-- > 0) { // Copy backwards *to-- = *from--; } }}
0 0
- System.arraycopy 本地方法 源代码分析
- System.arraycopy() 分析
- System.arraycopy 源码分析
- System.arraycopy()方法详解
- System.arraycopy 方法
- Java System.arraycopy()方法
- Java System.arraycopy()方法
- System.arraycopy方法详解
- System.arraycopy()方法详解
- System.arraycopy()方法详解
- System.arraycopy方法的使用
- java的System.arraycopy()方法
- System.arraycopy方法的使用
- System.arraycopy方法的使用
- System.arraycopy方法的使用
- System.arraycopy方法的使用
- System.arraycopy方法的使用
- System.arraycopy方法的使用
- spring的jdbc事务管理2
- mysql忘记密码,如何重新设置
- 数据库mysql导入数据
- 七牛上传文件 图片
- 传智播客:详解企业官网设计流程
- System.arraycopy 本地方法 源代码分析
- 《第一行代码——Android》之日志工具介绍
- 汽车之家代码片段
- 交情
- AngularJS中如何绑定html内容
- lua的类
- Android-连续按两次返回键实现应用程序退出
- instanceof
- 淘宝动态配置diamond-client 准备工作