java new字节码原理分析

1 篇文章 0 订阅
1 篇文章 0 订阅

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

例如:c++中是实例化一个对象分为二步,第一步开辟内存、第二步 调用构造函数init对象的属性信息.那么java new一个对象 都做哪些操作.这篇文档从字节码层面和jvm层面这二个角度来分析。


一、java的new一个对象的字节码

public class Demo{
    public static void main(String[] args) {
		Demo demo = new Demo();
	}
}
Constant pool: //常量池
  //类信息
   #2 = Class              #14            // Demo
   #3 = Methodref          #2.#13         // Demo."<init>":()V
   #14 = Utf8               Demo
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
        // 字节码是new,执行常量#2
         0: new           #2                  // class Demo
         //复制栈顶引用
         3: dup
         //消耗一个引用,触发调用构造方法 <init>
         4: invokespecial #3                  // Method "<init>":()V
         7: astore_1
         8: return
}

二、使jvm层面如何处理字节码new

1. jvm字节码解释器bytecodeInterpreter.cpp

代码如下(示例):

      CASE(_new): {
        u2 index = Bytes::get_Java_u2(pc+1);
        //获取ConstantPool
        ConstantPool* constants = istate->method()->constants();
        if (!constants->tag_at(index).is_unresolved_klass()) {
          //根据编译的常量池index查找
          Klass* entry = constants->slot_at(index).get_klass();
          ...
          InstanceKlass* ik = (InstanceKlass*) k_entry;
          ...
          //此处tlab(Slow case allocation有tlab介绍)及检测省略
          //设置对象头,偏向锁和synchronized原理相关此次不做解释
          if (UseBiasedLocking) {
                result->set_mark(ik->prototype_header());
          } else {
                result->set_mark(markOopDesc::prototype());
          }
           
        // Slow case allocation 
        CALL_VM(InterpreterRuntime::_new(THREAD, METHOD->constants(), index),
     ...
      }

2. 进入运行解释器new创建对象InterpreterRuntime.cpp

// Allocation 和c++类似 分配内存和设置初内存中初始化的值
IRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* thread, ConstantPool* pool, int index))
  Klass* k_oop = pool->klass_at(index, CHECK);
  instanceKlassHandle klass (THREAD, k_oop);
  klass->check_valid_for_instantiation(true, CHECK);
  // 加载 链接 解析 初始化 使用 销毁 确保初始化
  klass->initialize(CHECK);
  //分配内存
  oop obj = klass->allocate_instance(CHECK);
  thread->set_vm_result(obj);
IRT_END

3. 根据jvm手册初始化类的静态信息(调用static和static常量即jvm中clint)instaceKlass.cpp

void InstanceKlass::initialize(TRAPS) {
  if (this->should_be_initialized()) {
    HandleMark hm(THREAD);
    instanceKlassHandle this_oop(THREAD, this);
    //类是对象模板,初始化类信息
    initialize_impl(this_oop, CHECK);
  } 
}
void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
  // Make sure klass is linked (verified) before initializationn.
  //链接阶段 -此处不详细解析(链接方法都在此处)
  this_oop->link_class(CHECK);

  // refer to the JVM book page 47 for description of steps
  // Step 1  大多数为校验、验证之类 故省略
 ...
  // Step 8
	//调用clint(也即static块)------------
    this_oop->call_class_initializer(THREAD);
  }

4. 根据java类(jvm Klass)分配对象内存,类对象分配的模板.

instanceOop InstanceKlass::allocate_instance(TRAPS) {
  int size = size_helper();  // 计算需要的内存
  //调用CollectedHeap分配内存
  instanceOop  i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
  return i;
}
oop CollectedHeap::obj_allocate(KlassHandle klass, int size, TRAPS) {
 //分配内存都要在走一步,命名可以看出来
  HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
  //分配后置处理,
  post_allocation_setup_obj(klass, obj);
  return (oop)obj;
}

5. 分配对象慢路径,如下根据jvm设置的垃圾回收新生代和老年代的配置相关

HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {
 //首先从从tlab分配,edns区线程独占无须上锁
  HeapWord* result = NULL;
  if (UseTLAB) {
    result = allocate_from_tlab(klass, THREAD, size);
}
  //从堆中分配空间,ci
  result = Universe::heap()->mem_allocate(size,
                                        
  }

在这里插入图片描述

6. 并行分配器ParallelScavengeHeap.cpp

HeapWord* ParallelScavengeHeap::mem_allocate(
                                     size_t size,
                                     bool* gc_overhead_limit_was_exceeded) {


  HeapWord* result = young_gen()->allocate(size);

  uint loop_count = 0;
  uint gc_count = 0;
  int gclocker_stalled_count = 0;

  while (result == NULL) {

  
    {
      MutexLocker ml(Heap_lock);
      gc_count = Universe::heap()->total_collections();
      //年轻代分配
      result = young_gen()->allocate(size);
      if (result != NULL) {
        return result;
      }
      // If certain conditions hold, try allocating from the old gen.  尝试老年代分配
      result = mem_allocate_old_gen(size);
      if (result != NULL) {
        return result;
      }

      if (gclocker_stalled_count > GCLockerRetryAllocationCount) {
        return NULL;
      }

   //触发gc,将执行gc请求放入gc管理线程中队列中
    if (result == NULL) {
      // Generate a VM operation
      VM_ParallelGCFailedAllocation op(size, gc_count);
      VMThread::execute(&op);
      ...
}

7. 在年代带eden区分配

  // Allocation
  HeapWord* allocate(size_t word_size) {
    HeapWord* result = eden_space()->cas_allocate(word_size);
    return result;
  }
  
HeapWord* MutableSpace::cas_allocate(size_t size) {
  do {
    HeapWord* obj = top();
    if (pointer_delta(end(), obj) >= size) {
     //推动分配指针即可
      HeapWord* new_top = obj + size;
      HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj);
  ...
  } while (true);
}

8. 在old区分配(详细在gc的文章详细讲,此时在堆区分配到了内存)

HeapWord* ParallelScavengeHeap::mem_allocate_old_gen(size_t size) {
  if (!should_alloc_in_eden(size) || GC_locker::is_active_and_needs_gc()) {
    // Size is too big for eden, or gc is locked out.
    return old_gen()->allocate(size);
  }

  return NULL;
}

HeapWord* PSOldGen::allocate(size_t word_size) {
  assert_locked_or_safepoint(Heap_lock);
  HeapWord* res = allocate_noexpand(word_size);
  if (res == NULL) {
    res = expand_and_allocate(word_size);
  }
  // Allocations in the old generation need to be reported
  if (res != NULL) {
    ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
    //根据设置分配策略,在元数据区tenured分配
    heap->size_policy()->tenured_allocation(word_size);
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_41253524

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值