jvm源码解读--11 ldc指令的解读
写一个java文件
    public static void main(String[] args) {
        String str1="abc";
        String str2 ="abc";
        String str3=new String("abc");
        boolean b1= str1==str2;
        boolean b2= str1==str3;
    }
查看字节码code
0 ldc #4 <abc>
2 astore_1
3 ldc #4 <abc>
5 astore_2
6 new #5 <java/lang/String>
9 dup
10 ldc #4 <abc>
12 invokespecial #6 <java/lang/String.<init>>
15 astore_3
16 aload_1
17 aload_2
18 if_acmpne 25 (+7)
21 iconst_1
22 goto 26 (+4)
25 iconst_0
26 istore 4
28 aload_1
29 aload_3
30 if_acmpne 37 (+7)
33 iconst_1
34 goto 38 (+4)
37 iconst_0
38 istore 5
40 getstatic #7 <java/lang/System.out>
43 ldc #8 <helloworld!>
能看待这个一个是ldc #4,其中#4的类型是
JVM_CONSTANT_String
然后对于String类的解析,会比较明白,先加载java/lang/String类,在生成oop对象,而ldc #4查看字节码的解析如下:
void TemplateTable::ldc(bool wide) {
  transition(vtos, vtos);
  Label call_ldc, notFloat, notClass, Done;
  if (wide) {
    __ get_unsigned_2_byte_index_at_bcp(rbx, 1);
  } else {
    __ load_unsigned_byte(rbx, at_bcp(1));
  }
  __ get_cpool_and_tags(rcx, rax);
  const int base_offset = ConstantPool::header_size() * wordSize;
  const int tags_offset = Array<u1>::base_offset_in_bytes();
  // get type
  __ xorptr(rdx, rdx);
  __ movb(rdx, Address(rax, rbx, Address::times_1, tags_offset));
  // unresolved class - get the resolved class
  __ cmpl(rdx, JVM_CONSTANT_UnresolvedClass);
  __ jccb(Assembler::equal, call_ldc);
  // unresolved class in error (resolution failed) - call into runtime
  // so that the same error from first resolution attempt is thrown.
  __ cmpl(rdx, JVM_CONSTANT_UnresolvedClassInError);
  __ jccb(Assembler::equal, call_ldc);
  // resolved class - need to call vm to get java mirror of the class
  __ cmpl(rdx, JVM_CONSTANT_Class);
  __ jcc(Assembler::notEqual, notClass);
  __ bind(call_ldc);
  __ movl(rcx, wide);
  call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), rcx);
  __ push(atos);
  __ jmp(Done);
  __ bind(notClass);
  __ cmpl(rdx, JVM_CONSTANT_Float);
  __ jccb(Assembler::notEqual, notFloat);
  // ftos
  __ fld_s(    Address(rcx, rbx, Address::times_ptr, base_offset));
  __ push(ftos);
  __ jmp(Done);
  __ bind(notFloat);
#ifdef ASSERT
  { Label L;
    __ cmpl(rdx, JVM_CONSTANT_Integer);
    __ jcc(Assembler::equal, L);
    // String and Object are rewritten to fast_aldc
    __ stop("unexpected tag type in ldc");
    __ bind(L);
  }
#endif
  // itos JVM_CONSTANT_Integer only
  __ movl(rax, Address(rcx, rbx, Address::times_ptr, base_offset));
  __ push(itos);
  __ bind(Done);
}
就算加上了汇编完成的东西
----------------------------------------------------------------------
ldc 18 ldc [0x00000000033c7840, 0x00000000033c79a0] 352 bytes 0x00000000033c7840: push %rax
0x00000000033c7841: jmpq 0x00000000033c7870
0x00000000033c7846: sub $0x8,%rsp
0x00000000033c784a: vmovss %xmm0,(%rsp)
0x00000000033c784f: jmpq 0x00000000033c7870
0x00000000033c7854: sub $0x10,%rsp
0x00000000033c7858: vmovsd %xmm0,(%rsp)
0x00000000033c785d: jmpq 0x00000000033c7870
0x00000000033c7862: sub $0x10,%rsp
0x00000000033c7866: mov %rax,(%rsp)
0x00000000033c786a: jmpq 0x00000000033c7870
0x00000000033c786f: push %rax
0x00000000033c7870: movzbl 0x1(%r13),%ebx
0x00000000033c7875: mov -0x18(%rbp),%rcx
0x00000000033c7879: mov 0x8(%rcx),%rcx
0x00000000033c787d: mov 0x8(%rcx),%rcx
0x00000000033c7881: mov 0x8(%rcx),%rax
0x00000000033c7885: movzbl 0x4(%rax,%rbx,1),%edx
// unresolved class - get the resolved class
__ cmpl(rdx, JVM_CONSTANT_UnresolvedClass);
__ jccb(Assembler::equal, call_ldc);
0x00000000033c788a: cmp $0x64,%edx
0x00000000033c788d: je 0x00000000033c789d
// unresolved class in error state - call into runtime to throw the error
// from the first resolution attempt
__ cmpl(rdx, JVM_CONSTANT_UnresolvedClassInError);
__ jccb(Assembler::equal, call_ldc);
0x00000000033c788f: cmp $0x67,%edx
0x00000000033c7892: je 0x00000000033c789d
// resolved class - need to call vm to get java mirror of the class
__ cmpl(rdx, JVM_CONSTANT_Class);
__ jcc(Assembler::notEqual, notClass);
0x00000000033c7894: cmp $0x7,%edx
0x00000000033c7897: jne 0x00000000033c794d
__ movl(c_rarg1, wide); wide=false
0x00000000033c789d: mov $0x0,%edx
0x00000000033c78a2: callq 0x00000000033c78ac
0x00000000033c78a7: jmpq 0x00000000033c7947
0x00000000033c78ac: lea 0x8(%rsp),%rax
0x00000000033c78b1: mov %r13,-0x38(%rbp)
0x00000000033c78b5: mov %r15,%rcx
0x00000000033c78b8: mov %rbp,0x1e8(%r15)
0x00000000033c78bf: mov %rax,0x1d8(%r15)
0x00000000033c78c6: sub $0x20,%rsp
0x00000000033c78ca: test $0xf,%esp
0x00000000033c78d0: je 0x00000000033c78e8
0x00000000033c78d6: sub $0x8,%rsp
0x00000000033c78da: callq 0x000000006aad9cd0
0x00000000033c78df: add $0x8,%rsp
0x00000000033c78e3: jmpq 0x00000000033c78ed
0x00000000033c78e8: callq 0x000000006aad9cd0
0x00000000033c78ed: add $0x20,%rsp
0x00000000033c78f1: movabs $0x0,%r10
0x00000000033c78fb: mov %r10,0x1d8(%r15)
0x00000000033c7902: movabs $0x0,%r10
0x00000000033c790c: mov %r10,0x1e8(%r15)
0x00000000033c7913: cmpq $0x0,0x8(%r15)
0x00000000033c791b: je 0x00000000033c7926
0x00000000033c7921: jmpq 0x00000000033b07e0
0x00000000033c7926: mov 0x238(%r15),%rax
0x00000000033c792d: movabs $0x0,%r10
0x00000000033c7937: mov %r10,0x238(%r15)
0x00000000033c793e: mov -0x38(%rbp),%r13
0x00000000033c7942: mov -0x30(%rbp),%r14
0x00000000033c7946: retq
0x00000000033c7947: push %rax
0x00000000033c7948: jmpq 0x00000000033c796b
__ bind(notClass);
__ cmpl(rdx, JVM_CONSTANT_Float); 常量值为4
__ jccb(Assembler::notEqual, notFloat);
0x00000000033c794d: cmp $0x4,%edx
0x00000000033c7950: jne 0x00000000033c7966
0x00000000033c7952: vmovss 0x50(%rcx,%rbx,8),%xmm0
0x00000000033c7958: sub $0x8,%rsp
0x00000000033c795c: vmovss %xmm0,(%rsp)
0x00000000033c7961: jmpq 0x00000000033c796b __ bind(notFloat); 0x00000000033c7966: mov 0x50(%rcx,%rbx,8),%eax
0x00000000033c796a: push %rax //下一条指令取指
0x00000000033c796b: movzbl 0x2(%r13),%ebx
0x00000000033c7970: add $0x2,%r13
0x00000000033c7974: movabs $0x6b2143f0,%r10
0x00000000033c797e: jmpq *(%r10,%rbx,8)
0x00000000033c7982: nopw 0x0(%rax,%rax,1)
0x00000000033c7988: add %al,(%rax)
0x00000000033c798a: add %al,(%rax)
0x00000000033c798c: add %al,(%rax)
0x00000000033c798e: add %al,(%rax)
0x00000000033c7990: add %al,(%rax)
0x00000000033c7992: add %al,(%rax)
0x00000000033c7994: add %al,(%rax)
0x00000000033c7996: add %al,(%rax)
0x00000000033c7998: add %al,(%rax)
0x00000000033c799a: add %al,(%rax)
0x00000000033c799c: add %al,(%rax)
0x00000000033c799e: add %al,(%rax)
----------------------------------------------------------------------
也分析不出来,打断点始终打不到,对于ldc 加载类,却可以打到断点,真是迷惑,查了一圈看了一篇文章说会调用StringTable::intern
文章链接:iizhihu.com/question/60778124
但是也没说明白调用链,开头就直接说了
给出以下逻辑

查看源码也是在bytecodeInterpreter.cpp找到了这段内容
CASE(_ldc_w):
CASE(_ldc):
{
u2 index;
bool wide = false;
int incr = 2; // frequent case
if (opcode == Bytecodes::_ldc) {
index = pc[1];
} else {
index = Bytes::get_Java_u2(pc+1);
incr = 3;
wide = true;
} ConstantPool* constants = METHOD->constants();
switch (constants->tag_at(index).value()) {
case JVM_CONSTANT_Integer:
SET_STACK_INT(constants->int_at(index), 0);
break; case JVM_CONSTANT_Float:
SET_STACK_FLOAT(constants->float_at(index), 0);
break; case JVM_CONSTANT_String:
{
oop result = constants->resolved_references()->obj_at(index);
if (result == NULL) {
CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception);
SET_STACK_OBJECT(THREAD->vm_result(), 0);
THREAD->set_vm_result(NULL);
} else {
VERIFY_OOP(result);
SET_STACK_OBJECT(result, 0);
}
break;
} case JVM_CONSTANT_Class:
VERIFY_OOP(constants->resolved_klass_at(index)->java_mirror());
SET_STACK_OBJECT(constants->resolved_klass_at(index)->java_mirror(), 0);
break; case JVM_CONSTANT_UnresolvedClass:
case JVM_CONSTANT_UnresolvedClassInError:
CALL_VM(InterpreterRuntime::ldc(THREAD, wide), handle_exception);
SET_STACK_OBJECT(THREAD->vm_result(), 0);
THREAD->set_vm_result(NULL);
break; default: ShouldNotReachHere();
}
UPDATE_PC_AND_TOS_AND_CONTINUE(incr, 1);
}
这个在里面打不了断点呢,上便的逻辑一点都不清楚,如何是好? 这个cpp文件都是灰色的,最后有这个 #ifndef CC_INTERP ,感觉不是模板编译器,
那么,参考知乎的文章,打了断点 发现bytecode 是fast_aldc,并且要加载的字符串是"system",与ldc 指令对上了呢,没想明白怎么出来的一个_fast_ldc指令,对于指令的解析,已经看过了没有对应的Constant String ,tag保存的类型为08的,最后还是让我发现了,hotspot在方法链接的时候将ldc 重写成了_fast_aldc,自己没看方法重写的代码,不知道呢
为什么呢?其实这不怪你,因为这是在连接的时候重写了,自己没看这部分内容,看来还要补起来 // Rewrites a method given the index_map information
void Rewriter::scan_method(Method* method, bool reverse, bool* invokespecial_error) {
..
case Bytecodes::_ldc:
case Bytecodes::_fast_aldc: // if reverse=true
maybe_rewrite_ldc(bcp, prefix_length+1, false, reverse);
..
} // Rewrite some ldc bytecodes to _fast_aldc
void Rewriter::maybe_rewrite_ldc(address bcp, int offset, bool is_wide,
bool reverse) {
if (!reverse) {
assert((*bcp) == (is_wide ? Bytecodes::_ldc_w : Bytecodes::_ldc), "not ldc bytecode");
address p = bcp + offset;
int cp_index = is_wide ? Bytes::get_Java_u2(p) : (u1)(*p);
constantTag tag = _pool->tag_at(cp_index).value();
/**
* bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; }
* bool is_method_type() const { return _tag == JVM_CONSTANT_MethodType; }
* bool is_string() const { return _tag == JVM_CONSTANT_String; }
*/ if (tag.is_method_handle() || tag.is_method_type() || tag.is_string()) { int ref_index = cp_entry_to_resolved_references(cp_index);
if (is_wide) {
(*bcp) = Bytecodes::_fast_aldc_w;
assert(ref_index == (u2)ref_index, "index overflow");
Bytes::put_native_u2(p, ref_index);
} else {
(*bcp) = Bytecodes::_fast_aldc;//将ldc转化成_fast_aldc,这个你不看到这里,怎么也跟踪不到呢??
assert(ref_index == (u1)ref_index, "index overflow");
(*p) = (u1)ref_index;
}
}
} else {
Bytecodes::Code rewritten_bc =
(is_wide ? Bytecodes::_fast_aldc_w : Bytecodes::_fast_aldc);
if ((*bcp) == rewritten_bc) {
address p = bcp + offset;
int ref_index = is_wide ? Bytes::get_native_u2(p) : (u1)(*p);
int pool_index = resolved_references_entry_to_pool_index(ref_index);
if (is_wide) {
(*bcp) = Bytecodes::_ldc_w;
assert(pool_index == (u2)pool_index, "index overflow");
Bytes::put_Java_u2(p, pool_index);
} else {
(*bcp) = Bytecodes::_ldc;
assert(pool_index == (u1)pool_index, "index overflow");
(*p) = (u1)pool_index;
}
}
}
}
接着就是
那看ldc和fast_aldc的汇编器,这里面写着生成oop对象
// Fast path for caching oop constants.
void TemplateTable::fast_aldc(bool wide) {
transition(vtos, atos); Register result = rax;
Register tmp = rdx;
int index_size = wide ? sizeof(u2) : sizeof(u1); Label resolved; // We are resolved if the resolved reference cache entry contains a
// non-null object (String, MethodType, etc.)
assert_different_registers(result, tmp);
__ get_cache_index_at_bcp(tmp, 1, index_size);
__ load_resolved_reference_at_index(result, tmp);
__ testl(result, result);
__ jcc(Assembler::notZero, resolved); address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); // first time invocation - must resolve first
__ movl(tmp, (int)bytecode());
__ call_VM(result, entry, tmp); __ bind(resolved); if (VerifyOops) {
__ verify_oop(result);
}
}
如下
oop Bytecode_loadconstant::resolve_constant(TRAPS) const {
  assert(_method.not_null(), "must supply method to resolve constant");
  int index = raw_index();
  ConstantPool* constants = _method->constants();
  if (has_cache_index()) {
    return constants->resolve_cached_constant_at(index, THREAD);
  } else {
    return constants->resolve_constant_at(index, THREAD);
  }
}
---------------
  oop resolve_cached_constant_at(int cache_index, TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    return resolve_constant_at_impl(h_this, _no_index_sentinel, cache_index, THREAD);
  }
---------------
// Called to resolve constants in the constant pool and return an oop.
// Some constant pool entries cache their resolved oop. This is also
// called to create oops from constants to use in arguments for invokedynamic
oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) {
  oop result_oop = NULL;
  Handle throw_exception;
  if (cache_index == _possible_index_sentinel) {
    // It is possible that this constant is one which is cached in the objects.
    // We'll do a linear search.  This should be OK because this usage is rare.
    assert(index > 0, "valid index");
    cache_index = this_oop->cp_to_object_index(index);
  }
  assert(cache_index == _no_index_sentinel || cache_index >= 0, "");
  assert(index == _no_index_sentinel || index >= 0, "");
  if (cache_index >= 0) {
    result_oop = this_oop->resolved_references()->obj_at(cache_index);
    if (result_oop != NULL) {
      return result_oop;
      // That was easy...
    }
    index = this_oop->object_to_cp_index(cache_index);
  }
  jvalue prim_value;  // temp used only in a few cases below
  int tag_value = this_oop->tag_at(index).value();
  switch (tag_value) {
  case JVM_CONSTANT_UnresolvedClass:
  case JVM_CONSTANT_UnresolvedClassInError:
  case JVM_CONSTANT_Class:
    {
      assert(cache_index == _no_index_sentinel, "should not have been set");
      Klass* resolved = klass_at_impl(this_oop, index, CHECK_NULL);
      // ldc wants the java mirror.
      result_oop = resolved->java_mirror();
      break;
    }
  case JVM_CONSTANT_String:
    assert(cache_index != _no_index_sentinel, "should have been set");
    if (this_oop->is_pseudo_string_at(index)) {
      result_oop = this_oop->pseudo_string_at(index, cache_index);
      break;
    }
    result_oop = string_at_impl(this_oop, index, cache_index, CHECK_NULL);
    break;
  case JVM_CONSTANT_MethodHandleInError:
  case JVM_CONSTANT_MethodTypeInError:
    {
      Symbol* error = SystemDictionary::find_resolution_error(this_oop, index);
      guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
      ResourceMark rm;
      THROW_MSG_0(error, "");
      break;
    }
  case JVM_CONSTANT_MethodHandle:
    {
      int ref_kind                 = this_oop->method_handle_ref_kind_at(index);
      int callee_index             = this_oop->method_handle_klass_index_at(index);
      Symbol*  name =      this_oop->method_handle_name_ref_at(index);
      Symbol*  signature = this_oop->method_handle_signature_ref_at(index);
      if (PrintMiscellaneous)
        tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s",
                      ref_kind, index, this_oop->method_handle_index_at(index),
                      callee_index, name->as_C_string(), signature->as_C_string());
      KlassHandle callee;
      { Klass* k = klass_at_impl(this_oop, callee_index, CHECK_NULL);
        callee = KlassHandle(THREAD, k);
      }
      KlassHandle klass(THREAD, this_oop->pool_holder());
      Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
                                                                   callee, name, signature,
                                                                   THREAD);
      result_oop = value();
      if (HAS_PENDING_EXCEPTION) {
        save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL);
      }
      break;
    }
  case JVM_CONSTANT_MethodType:
    {
      Symbol*  signature = this_oop->method_type_signature_at(index);
      if (PrintMiscellaneous)
        tty->print_cr("resolve JVM_CONSTANT_MethodType [%d/%d] %s",
                      index, this_oop->method_type_index_at(index),
                      signature->as_C_string());
      KlassHandle klass(THREAD, this_oop->pool_holder());
      Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
      result_oop = value();
      if (HAS_PENDING_EXCEPTION) {
        save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL);
      }
      break;
    }
  case JVM_CONSTANT_Integer:
    assert(cache_index == _no_index_sentinel, "should not have been set");
    prim_value.i = this_oop->int_at(index);
    result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL);
    break;
  case JVM_CONSTANT_Float:
    assert(cache_index == _no_index_sentinel, "should not have been set");
    prim_value.f = this_oop->float_at(index);
    result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL);
    break;
  case JVM_CONSTANT_Long:
    assert(cache_index == _no_index_sentinel, "should not have been set");
    prim_value.j = this_oop->long_at(index);
    result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL);
    break;
  case JVM_CONSTANT_Double:
    assert(cache_index == _no_index_sentinel, "should not have been set");
    prim_value.d = this_oop->double_at(index);
    result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
    break;
  default:
    DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
                              this_oop(), index, cache_index, tag_value) );
    assert(false, "unexpected constant tag");
    break;
  }
  if (cache_index >= 0) {
    // Cache the oop here also.
    Handle result_handle(THREAD, result_oop);
    MonitorLockerEx ml(this_oop->lock());  // don't know if we really need this
    oop result = this_oop->resolved_references()->obj_at(cache_index);
    // Benign race condition:  resolved_references may already be filled in while we were trying to lock.
    // The important thing here is that all threads pick up the same result.
    // It doesn't matter which racing thread wins, as long as only one
    // result is used by all threads, and all future queries.
    // That result may be either a resolved constant or a failure exception.
    if (result == NULL) {
      this_oop->resolved_references()->obj_at_put(cache_index, result_handle());
      return result_handle();
    } else {
      // Return the winning thread's result.  This can be different than
      // result_handle() for MethodHandles.
      return result;
    }
  } else {
    return result_oop;
  }
}
-------------------
oop ConstantPool::string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS) {
  // If the string has already been interned, this entry will be non-null
  oop str = this_oop->resolved_references()->obj_at(obj_index);
  if (str != NULL) return str;
  Symbol* sym = this_oop->unresolved_string_at(which);
  str = StringTable::intern(sym, CHECK_(NULL));
  this_oop->string_at_put(which, obj_index, str);
  assert(java_lang_String::is_instance(str), "must be string");
  return str;
}
-----
oop StringTable::intern(Symbol* symbol, TRAPS) {
  if (symbol == NULL) return NULL;
  ResourceMark rm(THREAD);
  int length;
  jchar* chars = symbol->as_unicode(length);
  Handle string;
  oop result = intern(string, chars, length, CHECK_NULL);
  return result;
}
-----
oop StringTable::intern(Handle string_or_null, jchar* name,
                        int len, TRAPS) {
  unsigned int hashValue = hash_string(name, len);
  int index = the_table()->hash_to_index(hashValue);
  oop found_string = the_table()->lookup(index, name, len, hashValue);
  // Found
  if (found_string != NULL) return found_string;
  debug_only(StableMemoryChecker smc(name, len * sizeof(name[0])));
  assert(!Universe::heap()->is_in_reserved(name),
         "proposed name of symbol must be stable");
  Handle string;
  // try to reuse the string if possible
  if (!string_or_null.is_null()) {
    string = string_or_null;
  } else {
    string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
  }
  // Grab the StringTable_lock before getting the_table() because it could
  // change at safepoint.
  MutexLocker ml(StringTable_lock, THREAD);
  // Otherwise, add to symbol to table
  return the_table()->basic_add(index, string, name, len,
                                hashValue, CHECK_NULL);
}
-----
oop StringTable::basic_add(int index_arg, Handle string, jchar* name,
                           int len, unsigned int hashValue_arg, TRAPS) {
  assert(java_lang_String::equals(string(), name, len),
         "string must be properly initialized");
  // Cannot hit a safepoint in this function because the "this" pointer can move.
  No_Safepoint_Verifier nsv;
  // Check if the symbol table has been rehashed, if so, need to recalculate
  // the hash value and index before second lookup.
  unsigned int hashValue;
  int index;
  if (use_alternate_hashcode()) {
    hashValue = hash_string(name, len);
    index = hash_to_index(hashValue);
  } else {
    hashValue = hashValue_arg;
    index = index_arg;
  }
  // Since look-up was done lock-free, we need to check if another
  // thread beat us in the race to insert the symbol.
  oop test = lookup(index, name, len, hashValue); // calls lookup(u1*, int)
  if (test != NULL) {
    // Entry already added
    return test;
  }
  HashtableEntry<oop, mtSymbol>* entry = new_entry(hashValue, string());
  add_entry(index, entry);
  return string();
}
这下下就清楚了,这是气人,你重写代码,怎么不和我说一下呢
jvm源码解读--11 ldc指令的解读的更多相关文章
- JVM源码分析之javaagent原理完全解读
		概述 本文重点讲述javaagent的具体实现,因为它面向的是我们Java程序员,而且agent都是用Java编写的,不需要太多的C/C++编程基础,不过这篇文章里也会讲到JVMTIAgent(C实现 ... 
- JVM源码分析之javaagent原理完全解读--转
		原文地址:http://www.infoq.com/cn/articles/javaagent-illustrated 概述 本文重点讲述javaagent的具体实现,因为它面向的是我们Java程序员 ... 
- JVM 源码分析之 javaagent 原理完全解读
		转载:https://infoq.cn/article/javaagent-illustrated 本文重点讲述 javaagent 的具体实现,因为它面向的是我们 Java 程序员,而且 agent ... 
- JVM源码分析之SystemGC完全解读
		JVM源码分析之SystemGC完全解读 概述 JVM的GC一般情况下是JVM本身根据一定的条件触发的,不过我们还是可以做一些人为的触发,比如通过jvmti做强制GC,通过System.gc触发,还可 ... 
- JVM源码分析之堆外内存完全解读
		JVM源码分析之堆外内存完全解读 寒泉子 2016-01-15 17:26:16 浏览6837 评论0 阿里技术协会 摘要: 概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们 ... 
- JVM 源码解读之 CMS 何时会进行 Full GC
		t点击上方"涤生的博客",关注我 转载请注明原创出处,谢谢!如果读完觉得有收获的话,欢迎点赞加关注. 前言 本文内容是基于 JDK 8 在文章 JVM 源码解读之 CMS GC 触 ... 
- jvm源码解读--17 Java的wait()、notify()学习
		write and debug by 张艳涛 wait()和notify()的通常用法 A线程取得锁,执行wait(),释放锁; B线程取得锁,完成业务后执行notify(),再释放锁; B线程释放锁 ... 
- 从jvm源码看synchronized
		从jvm源码看synchronized 索引 synchronized的使用 修饰实例方法 修饰静态方法 修饰代码块 总结 Synchronzied的底层原理 对象头和内置锁(ObjectMonito ... 
- JVM源码分析-类加载场景实例分析
		A类调用B类的静态方法,除了加载B类,但是B类的一个未被调用的方法间接使用到的C类却也被加载了,这个有意思的场景来自一个提问:方法中使用的类型为何在未调用时尝试加载?. 场景如下: public cl ... 
随机推荐
- Redis源码解析之跳跃表(一)
			跳跃表(skiplist) 有序集合(sorted set)是Redis中较为重要的一种数据结构,从名字上来看,我们可以知道它相比一般的集合多了一个有序.Redis的有序集合会要求我们给定一个分值(s ... 
- 有了Java8的“+”真的可以不要StringBuilder了吗
			最近在头条上看到一篇帖子,说Java8开始,字符串拼接时,"+"会被编译成StringBuilder,所以,字符串的连接操作不用再考虑效率问题了,事实真的是这样吗?要搞明白,还是要 ... 
- Func委托与表达式树Expression
			最近在写ORM框架,其中遇到一个难点,就是作为框架调用方如何将查询条件传入框架内.其中就用到了Expression. Func委托 要Expression先要了解Func委托,Func委托的样式是: ... 
- IDEA打开文件时,关闭SonarLint自动扫描
			操作步骤 1 打开 Preferences mac快捷键:command+, 2 搜索 SonarLint,取消勾选Automatically trigger analysis,保存设置 
- 38、mysql数据库(pymysql及事务)
			38.1.python之pymysql模块: 1.说明: pymsql是Python中操作MySQL的模块,其使用方法和py2的MySQLdb几乎相同. 2.模块安装: pip install pym ... 
- 徒手从零实现 uTools 系列(三)- 屏幕取色和截屏
			前言 为了进一步提高开发工作效率,最近我们基于 electron 开发了一款媲美 uTools 的开源工具箱 rubick.该工具箱不仅仅开源,最重要的是可以使用 uTools 生态内所有开源插件!这 ... 
- webpack(4)webpack.config.js配置和package.json配置
			前言 上一篇文章我们使用webpack打包成功了,但是每次都要自己手动输入打包的文件地址和打包到哪里去的地址,非常麻烦,所以这里介绍使用配置文件进行打包 webpack.config.js 首先我们创 ... 
- linux~大文件相关操作的总结
			1.生成指定大小的文件 在当前目录下生成一个50M的文件: dd if=/dev/zero of=50M.file bs=1M count=50 truncate -s 2G ~/big.log.t ... 
- 0shell变量
			1.定义变量 2.使用变量 3.修改变量的值 4.将命令的结果赋值给变量 5.只读变量 6.删除变量 一.变量 1.定义变量 在 Bash shell 中,每一个变量的值都是字符串,无论你给变量赋值时 ... 
- python中的内置函数lambda map filter reduce
			p.p1 { margin: 0; font: 12px "Helvetica Neue" } p.p2 { margin: 0; font: 12px "Helveti ... 
