自学内容网 自学内容网

openjdk17 jvm 大对象 内存分配 在C++源码体现

##java大对象数组,计算260000长度引用类型数组大概占用1M左右空间

import java.util.ArrayList;
import java.util.List;

public class OutOfMemoryTest {

    public static void main(String[] args) {
        List<MiBigObject> miBigObjects = new ArrayList<>(260000);
        int length=0;
        while(true) {
            MiBigObject miBigObject = new MiBigObject();
            miBigObjects.add(miBigObject);
            System.out.println(length++);
        }
    }

}

public class MiBigObject {
}

##C++分配大对象数组内存GDB堆栈

#0  G1CollectedHeap::attempt_allocation_humongous (this=0x7ffff00453d0, word_size=130002) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/g1/g1CollectedHeap.cpp:826
#1  0x00007ffff61d65ee in G1CollectedHeap::mem_allocate (this=0x7ffff00453d0, word_size=130002, gc_overhead_limit_was_exceeded=0x7ffff7bfe570)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/g1/g1CollectedHeap.cpp:372
#2  0x00007ffff6779bf8 in MemAllocator::allocate_outside_tlab (this=0x7ffff7bfe5d0, allocation=...)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/memAllocator.cpp:258
#3  0x00007ffff677a023 in MemAllocator::mem_allocate (this=0x7ffff7bfe5d0, allocation=...) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/memAllocator.cpp:358
#4  0x00007ffff677a068 in MemAllocator::allocate (this=0x7ffff7bfe5d0) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/memAllocator.cpp:365
#5  0x00007ffff6019669 in CollectedHeap::array_allocate (this=0x7ffff00453d0, klass=0x100058458, size=130002, length=260000, do_zero=true, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/gc/shared/collectedHeap.inline.hpp:41
#6  0x00007ffff6344a7c in InstanceKlass::allocate_objArray (this=0x100041040, n=1, length=260000, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/oops/instanceKlass.cpp:1349
#7  0x00007ffff685c14e in oopFactory::new_objArray (klass=0x100041040, length=260000, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/oopFactory.cpp:122
#8  0x00007ffff6368710 in InterpreterRuntime::anewarray (current=0x7ffff0028920, pool=0x7fffd99038f0, index=7, size=260000)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/interpreter/interpreterRuntime.cpp:266
#9  0x00007fffe1023e51 in ?? ()
#10 0x00007fffe1023dc2 in ?? ()
#11 0x00000000ffa167e0 in ?? ()
#12 0x00007ffff7bfe730 in ?? ()
#13 0x00007fffd9908ed2 in ?? ()
#14 0x00007ffff7bfe790 in ?? ()
#15 0x00007fffd9aced80 in ?? ()
#16 0x0000000000000000 in ?? ()

##C++源码

HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
  ResourceMark rm; // For retrieving the thread names in log messages.

  // The structure of this method has a lot of similarities to
  // attempt_allocation_slow(). The reason these two were not merged
  // into a single one is that such a method would require several "if
  // allocation is not humongous do this, otherwise do that"
  // conditional paths which would obscure its flow. In fact, an early
  // version of this code did use a unified method which was harder to
  // follow and, as a result, it had subtle bugs that were hard to
  // track down. So keeping these two methods separate allows each to
  // be more readable. It will be good to keep these two in sync as
  // much as possible.

  assert_heap_not_locked_and_not_at_safepoint();
  assert(is_humongous(word_size), "attempt_allocation_humongous() "
         "should only be called for humongous allocations");

  // Humongous objects can exhaust the heap quickly, so we should check if we
  // need to start a marking cycle at each humongous object allocation. We do
  // the check before we do the actual allocation. The reason for doing it
  // before the allocation is that we avoid having to keep track of the newly
  // allocated memory while we do a GC.
  if (policy()->need_to_start_conc_mark("concurrent humongous allocation",
                                        word_size)) {
    collect(GCCause::_g1_humongous_allocation);
  }

  // We will loop until a) we manage to successfully perform the
  // allocation or b) we successfully schedule a collection which
  // fails to perform the allocation. b) is the only case when we'll
  // return NULL.
  HeapWord* result = NULL;
  for (uint try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
    bool should_try_gc;
    bool preventive_collection_required = false;
    uint gc_count_before;


    {
      MutexLocker x(Heap_lock);

      size_t size_in_regions = humongous_obj_size_in_regions(word_size);
      preventive_collection_required = policy()->preventive_collection_required((uint)size_in_regions);
      if (!preventive_collection_required) {
        // Given that humongous objects are not allocated in young
        // regions, we'll first try to do the allocation without doing a
        // collection hoping that there's enough space in the heap.
        result = humongous_obj_allocate(word_size);
        if (result != NULL) {
          policy()->old_gen_alloc_tracker()->
            add_allocated_humongous_bytes_since_last_gc(size_in_regions * HeapRegion::GrainBytes);
          return result;
        }
      }

      // Only try a GC if the GCLocker does not signal the need for a GC. Wait until
      // the GCLocker initiated GC has been performed and then retry. This includes
      // the case when the GC Locker is not active but has not been performed.
      should_try_gc = !GCLocker::needs_gc();
      // Read the GC count while still holding the Heap_lock.
      gc_count_before = total_collections();
    }

    if (should_try_gc) {
      GCCause::Cause gc_cause = preventive_collection_required ? GCCause::_g1_preventive_collection
                                                              : GCCause::_g1_humongous_allocation;
      bool succeeded;
      result = do_collection_pause(word_size, gc_count_before, &succeeded, gc_cause);
      if (result != NULL) {
        assert(succeeded, "only way to get back a non-NULL result");
        log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT,
                             Thread::current()->name(), p2i(result));
        size_t size_in_regions = humongous_obj_size_in_regions(word_size);
        policy()->old_gen_alloc_tracker()->
          record_collection_pause_humongous_allocation(size_in_regions * HeapRegion::GrainBytes);
        return result;
      }

      if (succeeded) {
        // We successfully scheduled a collection which failed to allocate. No
        // point in trying to allocate further. We'll just return NULL.
        log_trace(gc, alloc)("%s: Successfully scheduled collection failing to allocate "
                             SIZE_FORMAT " words", Thread::current()->name(), word_size);
        return NULL;
      }
      log_trace(gc, alloc)("%s: Unsuccessfully scheduled collection allocating " SIZE_FORMAT "",
                           Thread::current()->name(), word_size);
    } else {
      // Failed to schedule a collection.
      if (gclocker_retry_count > GCLockerRetryAllocationCount) {
        log_warning(gc, alloc)("%s: Retried waiting for GCLocker too often allocating "
                               SIZE_FORMAT " words", Thread::current()->name(), word_size);
        return NULL;
      }
      log_trace(gc, alloc)("%s: Stall until clear", Thread::current()->name());
      // The GCLocker is either active or the GCLocker initiated
      // GC has not yet been performed. Stall until it is and
      // then retry the allocation.
      GCLocker::stall_until_clear();
      gclocker_retry_count += 1;
    }


    // We can reach here if we were unsuccessful in scheduling a
    // collection (because another thread beat us to it) or if we were
    // stalled due to the GC locker. In either can we should retry the
    // allocation attempt in case another thread successfully
    // performed a collection and reclaimed enough space.
    // Humongous object allocation always needs a lock, so we wait for the retry
    // in the next iteration of the loop, unlike for the regular iteration case.
    // Give a warning if we seem to be looping forever.

    if ((QueuedAllocationWarningCount > 0) &&
        (try_count % QueuedAllocationWarningCount == 0)) {
      log_warning(gc, alloc)("%s: Retried allocation %u times for " SIZE_FORMAT " words",
                             Thread::current()->name(), try_count, word_size);
    }
  }

  ShouldNotReachHere();
  return NULL;
}


原文地址:https://blog.csdn.net/u014200244/article/details/144132903

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!