對(duì)象的創(chuàng)建以及YoungGC的觸發(fā)

對(duì)象的分配

大部分對(duì)象都在Heap(堆中進(jìn)行分配),Heap空間是共享的內(nèi)存空間窃躲,當(dāng)多個(gè)線程在Heap中為對(duì)象分配內(nèi)存空間時(shí)论悴,需要通過(guò)加鎖的方式進(jìn)行同步掖棉,為了提高對(duì)象分配的效率,對(duì)象在線程TLAB空間為對(duì)象分配內(nèi)存膀估。對(duì)象分配流程圖如下:


下面結(jié)合Hotspot源碼來(lái)分析對(duì)象內(nèi)存分配流程:

一般我們得代碼都是通過(guò)解釋器執(zhí)行幔亥,當(dāng)創(chuàng)建對(duì)象得時(shí)候,解釋器執(zhí)行 new 指令察纯,來(lái)到這里:openjdk\hotspot\src\share\vm\interpreter\interpreterRuntime.cpp

IRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* thread, constantPoolOopDesc* pool, int index))

  //從運(yùn)行時(shí)常量池中獲取KlassOop
  klassOop k_oop = pool->klass_at(index, CHECK);
  instanceKlassHandle klass (THREAD, k_oop);

  // 確保我們沒有實(shí)例化一個(gè)抽象的klass
  klass->check_valid_for_instantiation(true, CHECK);

  // 保證已經(jīng)完成類加載和初始化
  klass->initialize(CHECK);

  //分配對(duì)象
  oop obj = klass->allocate_instance(CHECK);
  thread->set_vm_result(obj);
IRT_END

上面的代碼中對(duì)創(chuàng)建的類的相關(guān)信息進(jìn)行驗(yàn)證(是否對(duì)以后抽象類進(jìn)行初始化帕棉,初始化的類是否加載),然后調(diào)用 allocate_instance 方法分配對(duì)象饼记,虛擬機(jī)調(diào)用跳轉(zhuǎn)到:openjdk\hotspot\src\share\vm\oops\instanceKlass.cpp

instanceOop instanceKlass::allocate_instance(TRAPS) {
  assert(!oop_is_instanceMirror(), "wrong allocation path");
  //是否重寫finalize()方法
  bool has_finalizer_flag = has_finalizer(); // Query before possible GC
  //分配的對(duì)象的大小
  int size = size_helper();  // Query before forming handle.

  KlassHandle h_k(THREAD, as_klassOop());

  instanceOop i;

  //分配對(duì)象
  i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
  if (has_finalizer_flag && !RegisterFinalizersAtInit) {
    i = register_finalizer(i, CHECK_NULL);
  }
  return i;
}

上面代碼主要判斷類是否重寫了finalize()香伴,重寫改方法的類是實(shí)例對(duì)象會(huì)加入finalize隊(duì)列,隊(duì)列里面的對(duì)象在GC前會(huì)調(diào)用finalize()方法具则,嘗試重新建立引用即纲,接下來(lái)調(diào)用size_helper()方法,計(jì)算需要分配的對(duì)象的空間大小博肋。然后調(diào)用CollectedHeap::obj_allocate(KlassHandle klass, int size, TRAPS)來(lái)為對(duì)象分配內(nèi)存低斋,源碼位置:openjdk\hotspot\src\share\vm\gc_interface\collectedHeap.inline.hpp,具體代碼如下:

//對(duì)象內(nèi)存空間分配
oop CollectedHeap::obj_allocate(KlassHandle klass, int size, TRAPS) {
  debug_only(check_for_valid_allocation_state());
  //校驗(yàn)在GC的時(shí)候不分配內(nèi)存
  assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");
  //分配大小大于0
  assert(size >= 0, "int won't convert to size_t");
  //內(nèi)存分配
  HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
  //初始化
  post_allocation_setup_obj(klass, obj);
  NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
  return (oop)obj;
}

上面的代碼中,對(duì)相關(guān)信息進(jìn)行驗(yàn)證匪凡,然后調(diào)用 common_mem_allocate_init 方法分配內(nèi)存膊畴,代碼如下:

HeapWord* CollectedHeap::common_mem_allocate_init(KlassHandle klass, size_t size, TRAPS) {
  //申請(qǐng)內(nèi)存
  HeapWord* obj = common_mem_allocate_noinit(klass, size, CHECK_NULL);
  //字節(jié)填充對(duì)齊
  init_obj(obj, size);
  return obj;
}

從上面的代碼可以看出,對(duì)象內(nèi)存的分配實(shí)際上是調(diào)用了common_mem_allocate_noinit 方法,在該方法中病游,會(huì)先嘗試在TLAB空間中分配內(nèi)存空間唇跨,(TLAB的相關(guān)資料可以參考:http://www.kejixun.com/article/170523/330012.shtml)如果失敗在堆中分配,如果在堆中也分配失敗衬衬,就會(huì)拋出OutOfMemoryError买猖,關(guān)鍵代碼如下:

HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {
  .............................
  HeapWord* result = NULL;
  if (UseTLAB) {//在TLAB中分配
    result = allocate_from_tlab(klass, THREAD, size);
    if (result != NULL) {
      assert(!HAS_PENDING_EXCEPTION,
             "Unexpected exception, will result in uninitialized storage");
      return result;
    }
  }
  bool gc_overhead_limit_was_exceeded = false;
  //在堆中分配
  result = Universe::heap()->mem_allocate(size,
                                          &gc_overhead_limit_was_exceeded);
  if (result != NULL) {
    NOT_PRODUCT(Universe::heap()->
      check_for_non_bad_heap_word_value(result, size));
    assert(!HAS_PENDING_EXCEPTION,
           "Unexpected exception, will result in uninitialized storage");
    THREAD->incr_allocated_bytes(size * HeapWordSize);
    AllocTracer::send_allocation_outside_tlab_event(klass, size * HeapWordSize);

    return result;
  }
    ..............................
    THROW_OOP_0(Universe::out_of_memory_error_gc_overhead_limit());
  }
}

上面的代碼段中,首先調(diào)用 allocate_from_tlab 方法佣耐,嘗試在TLAB空間分配對(duì)象政勃,如果內(nèi)存分配失敗,調(diào)用 mem_allocate 方法兼砖,在 eden 區(qū)中分配內(nèi)存空間奸远,下面分別來(lái)查看這兩個(gè)方法的具體實(shí)現(xiàn)既棺。

HeapWord* CollectedHeap::allocate_from_tlab(KlassHandle klass, Thread* thread, size_t size) {
  assert(UseTLAB, "should use UseTLAB");
  //TLAB分配
  HeapWord* obj = thread->tlab().allocate(size);
  if (obj != NULL) {
    return obj;
  }
  // Otherwise..
  //慢分配
  return allocate_from_tlab_slow(klass, thread, size);
}

在TLAB空間如果分配成功就直接返回該對(duì)象,如果TLAB空間不足懒叛,就會(huì)分配失敗丸冕,調(diào)用 allocate_from_tlab_slow,重新申請(qǐng)一片TLAB空間進(jìn)行內(nèi)存的分配薛窥。

HeapWord* CollectedHeap::allocate_from_tlab_slow(KlassHandle klass, Thread* thread, size_t size) {

  // Retain tlab and allocate object in shared space if
  // the amount free in the tlab is too large to discard.
  //當(dāng)tlab中剩余空間>設(shè)置的可忽略大小以及申請(qǐng)一塊新的tlab失敗時(shí)返回null,然后走上面的第二步胖烛,
  //也就是在堆的共享區(qū)域分配。當(dāng)tlab剩余空間可以忽略诅迷,則申請(qǐng)一塊新的tlab佩番,若申請(qǐng)成功,則在此tlab上分配罢杉。 
  if (thread->tlab().free() > thread->tlab().refill_waste_limit()) {
    thread->tlab().record_slow_allocation(size);
    return NULL;
  }

  // Discard tlab and allocate a new one.
  // To minimize fragmentation, the last TLAB may be smaller than the rest.
  //重新申請(qǐng)一塊TLAB
  size_t new_tlab_size = thread->tlab().compute_size(size);
  thread->tlab().clear_before_allocation();
  if (new_tlab_size == 0) {
    return NULL;
  }
  // 對(duì)象分配
  // Allocate a new TLAB...
  HeapWord* obj = Universe::heap()->allocate_new_tlab(new_tlab_size);
  if (obj == NULL) {
    return NULL;
  }

  AllocTracer::send_allocation_in_new_tlab_event(klass, new_tlab_size * HeapWordSize, size * HeapWordSize);
  ....................................
  return obj;
}

如果在TLAB空間分配失敗趟畏,就會(huì)調(diào)用 mem_allocate 方法在eden空間分配內(nèi)存,該方法內(nèi)部通過(guò)調(diào)用 mem_allocate_work 方法滩租,在該方法中具體實(shí)現(xiàn)內(nèi)存分配的細(xì)節(jié)赋秀,源碼文件openjdk\hotspot\src\share\vm\memory\collectorPolicy.cpp:

HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size,
                                        bool is_tlab,
                                        bool* gc_overhead_limit_was_exceeded) {
  GenCollectedHeap *gch = GenCollectedHeap::heap();

  debug_only(gch->check_for_valid_allocation_state());
  assert(gch->no_gc_in_progress(), "Allocation during gc not allowed");

  // In general gc_overhead_limit_was_exceeded should be false so
  // set it so here and reset it to true only if the gc time
  // limit is being exceeded as checked below.
  *gc_overhead_limit_was_exceeded = false;

  HeapWord* result = NULL;

  // Loop until the allocation is satisified,
  // or unsatisfied after GC.
  for (int try_count = 1; /* return or throw */; try_count += 1) {
    HandleMark hm; // discard any handles allocated in each iteration

    // First allocation attempt is lock-free.
    //第一次嘗試分配不需要獲取鎖,通過(guò)while+CAS來(lái)進(jìn)行分配
    Generation *gen0 = gch->get_gen(0);
    assert(gen0->supports_inline_contig_alloc(),
      "Otherwise, must do alloc within heap lock");
    if (gen0->should_allocate(size, is_tlab)) {//對(duì)大小進(jìn)行判斷律想,比如是否超過(guò)eden區(qū)能分配的最大大小
      result = gen0->par_allocate(size, is_tlab);///while循環(huán)+指針碰撞+CAS分配
      if (result != NULL) {
        assert(gch->is_in_reserved(result), "result not in heap");
        return result;
      }
    }
    //如果res=null,表示在eden區(qū)分配失敗了猎莲,因?yàn)闆]有連續(xù)的空間。則繼續(xù)往下走
    unsigned int gc_count_before;  // read inside the Heap_lock locked region
    {
      MutexLocker ml(Heap_lock);//鎖
      if (PrintGC && Verbose) {
        gclog_or_tty->print_cr("TwoGenerationCollectorPolicy::mem_allocate_work:"
                      " attempting locked slow path allocation");
      }
      // Note that only large objects get a shot at being
      // allocated in later generations.
       //需要注意的是技即,只有大對(duì)象可以被分配在老年代著洼。一般情況下都是false,所以first_only=true
      bool first_only = ! should_try_older_generation_allocation(size);
      //在年輕代分配
      result = gch->attempt_allocation(size, is_tlab, first_only);
      if (result != NULL) {
        assert(gch->is_in_reserved(result), "result not in heap");
        return result;
      }
      /*Gc操作已被觸發(fā)但還無(wú)法被執(zhí)行,一般不會(huì)出現(xiàn)這種情況,只有在jni中jni_GetStringCritical等
      方法被調(diào)用時(shí)出現(xiàn)is_active_and_needs_gc=TRUE姥份,主要是為了避免GC導(dǎo)致對(duì)象地址改變郭脂。
      jni_GetStringCritical方法的作用參考文章:http://blog.csdn.net/xyang81/article/details/42066665
      */
      if (GC_locker::is_active_and_needs_gc()) {
        if (is_tlab) {
          return NULL;  // Caller will retry allocating individual object
        }
        if (!gch->is_maximal_no_gc()) {////因?yàn)椴荒苓M(jìn)行GC回收年碘,所以只能嘗試通過(guò)擴(kuò)堆
          // Try and expand heap to satisfy request
          result = expand_heap_and_allocate(size, is_tlab);
          // result could be null if we are out of space
          if (result != NULL) {
            return result;
          }
        }

        // If this thread is not in a jni critical section, we stall
        // the requestor until the critical section has cleared and
        // GC allowed. When the critical section clears, a GC is
        // initiated by the last thread exiting the critical section; so
        // we retry the allocation sequence from the beginning of the loop,
        // rather than causing more, now probably unnecessary, GC attempts.
        JavaThread* jthr = JavaThread::current();
        if (!jthr->in_critical()) {
          MutexUnlocker mul(Heap_lock);
          // Wait for JNI critical section to be exited
          GC_locker::stall_until_clear();
          continue;
        } else {
          if (CheckJNICalls) {
            fatal("Possible deadlock due to allocating while"
                  " in jni critical section");
          }
          return NULL;
        }
      }

      // Read the gc count while the heap lock is held.
      gc_count_before = Universe::heap()->total_collections();
    }
    //VM操作進(jìn)行一次由分配失敗觸發(fā)的GC
    VM_GenCollectForAllocation op(size,
                                  is_tlab,
                                  gc_count_before);
    VMThread::execute(&op);
    if (op.prologue_succeeded()) {////一次GC操作已完成
      result = op.result();
      if (op.gc_locked()) {
         assert(result == NULL, "must be NULL if gc_locked() is true");
         continue;  // retry and/or stall as necessary
      }

      // Allocation has failed and a collection
      // has been done.  If the gc time limit was exceeded the
      // this time, return NULL so that an out-of-memory
      // will be thrown.  Clear gc_overhead_limit_exceeded
      // so that the overhead exceeded does not persist.

    /* 
      分配失敗且已經(jīng)完成GC了澈歉,則判斷是否超時(shí)等信息。
       */
      const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded();
      const bool softrefs_clear = all_soft_refs_clear();
      assert(!limit_exceeded || softrefs_clear, "Should have been cleared");
      if (limit_exceeded && softrefs_clear) {
        *gc_overhead_limit_was_exceeded = true;
        size_policy()->set_gc_overhead_limit_exceeded(false);
        if (op.result() != NULL) {
          CollectedHeap::fill_with_object(op.result(), size);
        }
        return NULL;
      }
      assert(result == NULL || gch->is_in_reserved(result),
             "result not in heap");
      return result;
    }

    // Give a warning if we seem to be looping forever.
    if ((QueuedAllocationWarningCount > 0) &&
        (try_count % QueuedAllocationWarningCount == 0)) {
          warning("TwoGenerationCollectorPolicy::mem_allocate_work retries %d times \n\t"
                  " size=%d %s", try_count, size, is_tlab ? "(TLAB)" : "");
    }
  }
}

YoungGC觸發(fā)

在年輕代嘗試對(duì)象的分配屿衅,如果對(duì)象分配失敗埃难,就觸發(fā)一次YoungGC,YoungGC的觸發(fā)是通過(guò)創(chuàng)建一個(gè)VM_GenCollectForAllocation涤久,調(diào)用VMThread的 execute 方法來(lái)觸發(fā)一次YoungGC涡尘。進(jìn)入execute方法,由于execute方法太長(zhǎng),下面只貼關(guān)鍵部分,源碼地址:

if (op->evaluate_at_safepoint() && !SafepointSynchronize::is_at_safepoint()) {
      SafepointSynchronize::begin();//驅(qū)使所有線程進(jìn)入safepoint然后掛起他們
      op->evaluate();//調(diào)用vm_operation的doit()方法進(jìn)行回收
      SafepointSynchronize::end();////喚醒所有的線程响迂,在safepoint執(zhí)行之后考抄,讓這些線程重新恢復(fù)執(zhí)行
 } else {
      op->evaluate();
 }

調(diào)用VM_Operation的 evaluate,源碼地址:openjdk\hotspot\src\share\vm\runtime\vm_operations.cpp

void VM_Operation::evaluate() {
  ResourceMark rm;
  if (TraceVMOperation) {
    tty->print("[");
    NOT_PRODUCT(print();)
  }
  //實(shí)際進(jìn)行操作的方法
  doit();
  if (TraceVMOperation) {
    tty->print_cr("]");
  }
}

主要是調(diào)用了VM_GenCollectForAllocation的 doit() 方法進(jìn)行GC蔗彤,源碼地址:openjdk\hotspot\src\share\vm\gc_implementation\shared\vmGCOperations.cpp

void VM_GenCollectForAllocation::doit() {
  SvcGCMarker sgcm(SvcGCMarker::MINOR);

  GenCollectedHeap* gch = GenCollectedHeap::heap();
  GCCauseSetter gccs(gch, _gc_cause);
  //通知內(nèi)存堆管理器處理一次內(nèi)存分配失敗
  _res = gch->satisfy_failed_allocation(_size, _tlab);//res=分配的結(jié)果,垃圾回收過(guò)程
  assert(gch->is_in_reserved_or_null(_res), "result not in heres=分配的結(jié)果ap");

  if (_res == NULL && GC_locker::is_active_and_needs_gc()) {
    set_gc_locked();
  }
}

從上面的代碼可以看出是調(diào)用satisfy_failed_allocation 方法川梅,在該方法中調(diào)用垃圾回收的相關(guān)方法疯兼。深入到該方法中,源碼地址:openjdk\hotspot\src\share\vm\memory\genCollectedHeap.cpp

HeapWord* GenCollectedHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {
  return collector_policy()->satisfy_failed_allocation(size, is_tlab);
}

獲得程序設(shè)置的垃圾回收器類型贫途,調(diào)用satisfy_failed_allocation方法吧彪,進(jìn)行垃圾回收,查看關(guān)鍵代碼丢早,源碼位置:openjdk\hotspot\src\share\vm\memory\collectorPolicy.cpp

if (GC_locker::is_active_and_needs_gc()) {////表示有jni在操作內(nèi)存姨裸,此時(shí)不能進(jìn)行GC避免改變對(duì)象在內(nèi)存的位置
    // GC locker is active; instead of a collection we will attempt
    // to expand the heap, if there's room for expansion.
    if (!gch->is_maximal_no_gc()) {
      result = expand_heap_and_allocate(size, is_tlab);//擴(kuò)堆
    }
    return result;   // could be null if we are out of space
    
    //consult_young=true的時(shí)候,表示調(diào)用該方法時(shí)怨酝,判斷此時(shí)晉升是否的安全的傀缩。
    //若=false,表示只取上次young gc時(shí)設(shè)置的參數(shù)农猬,此次不再進(jìn)行額外的判斷扑毡。
  } else if (!gch->incremental_collection_will_fail(false /* don't consult_young */)) {
    // Do an incremental collection.
    gch->do_collection(false            /* full */,
                       false            /* clear_all_soft_refs */,
                       size             /* size */,
                       is_tlab          /* is_tlab */,
                       number_of_generations() - 1 /* max_level */);
  } else {
    if (Verbose && PrintGCDetails) {
      gclog_or_tty->print(" :: Trying full because partial may fail :: ");
    }
    // Try a full collection; see delta for bug id 6266275
    // for the original code and why this has been simplified
    // with from-space allocation criteria modified and
    // such allocation moved out of the safepoint path.
    gch->do_collection(true             /* full */,
                       false            /* clear_all_soft_refs */,
                       size             /* size */,
                       is_tlab          /* is_tlab */,
                       number_of_generations() - 1 /* max_level */);
  }

  result = gch->attempt_allocation(size, is_tlab, false /*first_only*/);

  if (result != NULL) {
    assert(gch->is_in_reserved(result), "result not in heap");
    return result;
  }

調(diào)用GenCollectedHeap::do_collection 方法進(jìn)行垃圾回收,該方法代碼太長(zhǎng)盛险,截取關(guān)鍵代碼:

_gens[i]->collect(full, do_clear_all_soft_refs, size, is_tlab);

下面主要查看 DefNewGeneration 進(jìn)行垃圾回收的代碼瞄摊,對(duì)應(yīng)的是SerialGC垃圾回收器,關(guān)鍵代碼如下:

//尋找GCRoots
gch->gen_process_strong_roots(_level,
                                true,  // Process younger gens, if any,
                                       // as strong roots.
                                true,  // activate StrongRootsScope
                                false, // not collecting perm generation.
                                SharedHeap::SO_AllClasses,
                                &fsc_with_no_gc_barrier,
                                true,   // walk *all* scavengable nmethods
                                &fsc_with_gc_barrier);

  //從GCRoots進(jìn)行遍歷苦掘,標(biāo)記存活的對(duì)象
  evacuate_followers.do_void();

關(guān)于YoungGC的具體執(zhí)行算法可以參考:http://hllvm.group.iteye.com/group/topic/39376
http://www.reibang.com/p/9af1a63a33c3

自我介紹

我是何勇换帜,現(xiàn)在重慶豬八戒,多學(xué)學(xué):追取9咄铡!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末递瑰,一起剝皮案震驚了整個(gè)濱河市祟牲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抖部,老刑警劉巖说贝,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異慎颗,居然都是意外死亡乡恕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門俯萎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)傲宜,“玉大人,你說(shuō)我怎么就攤上這事夫啊『洌” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵撇眯,是天一觀的道長(zhǎng)报嵌。 經(jīng)常有香客問(wèn)我躁愿,道長(zhǎng),這世上最難降的妖魔是什么沪蓬? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任彤钟,我火速辦了婚禮,結(jié)果婚禮上跷叉,老公的妹妹穿的比我還像新娘逸雹。我一直安慰自己,他們只是感情好云挟,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布梆砸。 她就那樣靜靜地躺著,像睡著了一般园欣。 火紅的嫁衣襯著肌膚如雪帖世。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天沸枯,我揣著相機(jī)與錄音日矫,去河邊找鬼。 笑死绑榴,一個(gè)胖子當(dāng)著我的面吹牛哪轿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播翔怎,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼窃诉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赤套?” 一聲冷哼從身側(cè)響起飘痛,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎容握,沒想到半個(gè)月后宣脉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唯沮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年脖旱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片介蛉。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖溶褪,靈堂內(nèi)的尸體忽然破棺而出币旧,到底是詐尸還是另有隱情,我是刑警寧澤猿妈,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布吹菱,位于F島的核電站巍虫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鳍刷。R本人自食惡果不足惜占遥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望输瓜。 院中可真熱鬧瓦胎,春花似錦、人聲如沸尤揣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)北戏。三九已至负芋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嗜愈,已是汗流浹背旧蛾。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蠕嫁,地道東北人蚜点。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拌阴,于是被迫代替她去往敵國(guó)和親绍绘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 概述 在JDK1.9中移除了JDK 8中已棄用的垃圾收集器(GC)組合迟赃,官網(wǎng)原始文檔如下: Removes gar...
    heyong閱讀 2,526評(píng)論 0 4
  • TLAB整理 HotSpot VM在JAVA堆中對(duì)象創(chuàng)建,布局,訪問(wèn)全過(guò)程(僅限于普通java對(duì)象,不包括數(shù)組和C...
    andersonoy閱讀 3,035評(píng)論 0 2
  • 簡(jiǎn)書 占小狼轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處陪拘,謝謝! 背景 介紹TLAB之前先思考一個(gè)問(wèn)題:創(chuàng)建對(duì)象時(shí)纤壁,需要在堆上申請(qǐng)指定大小的...
    美團(tuán)Java閱讀 14,406評(píng)論 18 64
  • 簡(jiǎn)書 占小狼轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處酌媒,謝謝欠痴! 本文由臧秀濤撰稿,經(jīng)過(guò)R大潤(rùn)色秒咨,由占小狼傾情分享喇辽,這些分析總結(jié)道出了TLA...
    美團(tuán)Java閱讀 9,541評(píng)論 2 36
  • 文:小耳機(jī)七七 影評(píng)《陸垚知馬俐》 兩個(gè)人菩咨,一個(gè)高傲,一個(gè)自卑,明明相愛抽米,卻在徘徊中丟失了那么多美好的時(shí)光特占。那些錯(cuò)...
    小七七大哈哈閱讀 942評(píng)論 4 12