Mercurial > hg > openjdk > jdk7u > hotspot
changeset 4562:88e43f47a8da hs24-b49
Merge
author | amurillo |
---|---|
date | Thu, 13 Jun 2013 10:26:22 -0700 |
parents | aa8623d58971 (current diff) b43a5b3a4249 (diff) |
children | 241ab36a8b84 |
files | src/share/vm/memory/klassInfoClosure.hpp |
diffstat | 40 files changed, 1159 insertions(+), 431 deletions(-) [+] |
line wrap: on
line diff
--- a/make/hotspot_version Wed Jun 12 19:58:20 2013 -0700 +++ b/make/hotspot_version Thu Jun 13 10:26:22 2013 -0700 @@ -35,7 +35,7 @@ HS_MAJOR_VER=24 HS_MINOR_VER=0 -HS_BUILD_NUMBER=48 +HS_BUILD_NUMBER=49 JDK_MAJOR_VER=1 JDK_MINOR_VER=7
--- a/src/cpu/sparc/vm/assembler_sparc.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/cpu/sparc/vm/assembler_sparc.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -3958,7 +3958,8 @@ if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) { // No allocation in the shared eden. - ba_short(slow_case); + ba(slow_case); + delayed()->nop(); } else { // get eden boundaries // note: we need both top & top_addr!
--- a/src/os/bsd/vm/os_bsd.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/bsd/vm/os_bsd.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -2889,6 +2889,13 @@ } } +static void warn_fail_commit_memory(char* addr, size_t size, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (errno=%d)", addr, size, exec, + strerror(err), err); +} + // NOTE: Bsd kernel does not really reserve the pages for us. // All it does is to check if there are enough free pages // left at the time of mmap(). This could be a potential @@ -2897,12 +2904,22 @@ int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; #ifdef __OpenBSD__ // XXX: Work-around mmap/MAP_FIXED bug temporarily on OpenBSD - return ::mprotect(addr, size, prot) == 0; + if (::mprotect(addr, size, prot) == 0) { + return true; + } #else uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); - return res != (uintptr_t) MAP_FAILED; + if (res != (uintptr_t) MAP_FAILED) { + return true; + } #endif + + // Warn about any commit errors we see in non-product builds just + // in case mmap() doesn't work as described on the man page. + NOT_PRODUCT(warn_fail_commit_memory(addr, size, exec, errno);) + + return false; } #ifndef _ALLBSD_SOURCE @@ -2930,7 +2947,25 @@ } #endif - return commit_memory(addr, size, exec); + // alignment_hint is ignored on this OS + return pd_commit_memory(addr, size, exec); +} + +void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + if (!pd_commit_memory(addr, size, exec)) { + // add extra info in product mode for vm_exit_out_of_memory(): + PRODUCT_ONLY(warn_fail_commit_memory(addr, size, exec, errno);) + vm_exit_out_of_memory(size, mesg); + } +} + +void os::pd_commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, bool exec, + const char* mesg) { + // alignment_hint is ignored on this OS + pd_commit_memory_or_exit(addr, size, exec, mesg); } void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { @@ -3097,7 +3132,7 @@ } bool os::pd_create_stack_guard_pages(char* addr, size_t size) { - return os::commit_memory(addr, size); + return os::commit_memory(addr, size, !ExecMem); } // If this is a growable mapping, remove the guard pages entirely by @@ -3432,21 +3467,20 @@ } // The memory is committed - address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); - MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); return addr; } bool os::release_memory_special(char* base, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); if (rslt == 0) { - MemTracker::record_virtual_memory_uncommit((address)base, bytes); - MemTracker::record_virtual_memory_release((address)base, bytes); + tkr.record((address)base, bytes); return true; } else { + tkr.discard(); return false; } @@ -4666,7 +4700,7 @@ if (!UseMembar) { address mem_serialize_page = (address) ::mmap(NULL, Bsd::page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - guarantee( mem_serialize_page != NULL, "mmap Failed for memory serialize page"); + guarantee( mem_serialize_page != MAP_FAILED, "mmap Failed for memory serialize page"); os::set_memory_serialize_page( mem_serialize_page ); #ifndef PRODUCT
--- a/src/os/bsd/vm/perfMemory_bsd.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/bsd/vm/perfMemory_bsd.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ } // commit memory - if (!os::commit_memory(mapAddress, size)) { + if (!os::commit_memory(mapAddress, size, !ExecMem)) { if (PrintMiscellaneous && Verbose) { warning("Could not commit PerfData memory\n"); } @@ -755,8 +755,7 @@ (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); return mapAddress; } @@ -918,8 +917,7 @@ } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); *addr = mapAddress; *sizep = size;
--- a/src/os/linux/vm/os_linux.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/linux/vm/os_linux.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -2640,11 +2640,49 @@ } } +static bool recoverable_mmap_error(int err) { + // See if the error is one we can let the caller handle. This + // list of errno values comes from JBS-6843484. I can't find a + // Linux man page that documents this specific set of errno + // values so while this list currently matches Solaris, it may + // change as we gain experience with this failure mode. + switch (err) { + case EBADF: + case EINVAL: + case ENOTSUP: + // let the caller deal with these errors + return true; + + default: + // Any remaining errors on this OS can cause our reserved mapping + // to be lost. That can cause confusion where different data + // structures think they have the same memory mapped. The worst + // scenario is if both the VM and a library think they have the + // same memory mapped. + return false; + } +} + +static void warn_fail_commit_memory(char* addr, size_t size, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (errno=%d)", addr, size, exec, + strerror(err), err); +} + +static void warn_fail_commit_memory(char* addr, size_t size, + size_t alignment_hint, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, size, + alignment_hint, exec, strerror(err), err); +} + // NOTE: Linux kernel does not really reserve the pages for us. // All it does is to check if there are enough free pages // left at the time of mmap(). This could be a potential // problem. -bool os::pd_commit_memory(char* addr, size_t size, bool exec) { +int os::Linux::commit_memory_impl(char* addr, size_t size, bool exec) { int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); @@ -2652,9 +2690,32 @@ if (UseNUMAInterleaving) { numa_make_global(addr, size); } - return true; - } - return false; + return 0; + } + + int err = errno; // save errno from mmap() call above + + if (!recoverable_mmap_error(err)) { + warn_fail_commit_memory(addr, size, exec, err); + vm_exit_out_of_memory(size, "committing reserved memory."); + } + + return err; +} + +bool os::pd_commit_memory(char* addr, size_t size, bool exec) { + return os::Linux::commit_memory_impl(addr, size, exec) == 0; +} + +void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + int err = os::Linux::commit_memory_impl(addr, size, exec); + if (err != 0) { + // the caller wants all commit errors to exit with the specified mesg: + warn_fail_commit_memory(addr, size, exec, err); + vm_exit_out_of_memory(size, mesg); + } } // Define MAP_HUGETLB here so we can build HotSpot on old systems. @@ -2667,8 +2728,9 @@ #define MADV_HUGEPAGE 14 #endif -bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, - bool exec) { +int os::Linux::commit_memory_impl(char* addr, size_t size, + size_t alignment_hint, bool exec) { + int err; if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; uintptr_t res = @@ -2679,16 +2741,45 @@ if (UseNUMAInterleaving) { numa_make_global(addr, size); } - return true; + return 0; + } + + err = errno; // save errno from mmap() call above + + if (!recoverable_mmap_error(err)) { + // However, it is not clear that this loss of our reserved mapping + // happens with large pages on Linux or that we cannot recover + // from the loss. For now, we just issue a warning and we don't + // call vm_exit_out_of_memory(). This issue is being tracked by + // JBS-8007074. + warn_fail_commit_memory(addr, size, alignment_hint, exec, err); +// vm_exit_out_of_memory(size, "committing reserved memory."); } // Fall through and try to use small pages } - if (commit_memory(addr, size, exec)) { + err = os::Linux::commit_memory_impl(addr, size, exec); + if (err == 0) { realign_memory(addr, size, alignment_hint); - return true; - } - return false; + } + return err; +} + +bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, + bool exec) { + return os::Linux::commit_memory_impl(addr, size, alignment_hint, exec) == 0; +} + +void os::pd_commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + int err = os::Linux::commit_memory_impl(addr, size, alignment_hint, exec); + if (err != 0) { + // the caller wants all commit errors to exit with the specified mesg: + warn_fail_commit_memory(addr, size, alignment_hint, exec, err); + vm_exit_out_of_memory(size, mesg); + } } void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { @@ -2706,7 +2797,7 @@ // small pages on top of the SHM segment. This method always works for small pages, so we // allow that in any case. if (alignment_hint <= (size_t)os::vm_page_size() || !UseSHM) { - commit_memory(addr, bytes, alignment_hint, false); + commit_memory(addr, bytes, alignment_hint, !ExecMem); } } @@ -2959,7 +3050,7 @@ ::munmap((void*)stack_extent, (uintptr_t)addr - stack_extent); } - return os::commit_memory(addr, size); + return os::commit_memory(addr, size, !ExecMem); } // If this is a growable mapping, remove the guard pages entirely by @@ -3080,7 +3171,7 @@ MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, -1, 0); - if (p != (void *) -1) { + if (p != MAP_FAILED) { // We don't know if this really is a huge page or not. FILE *fp = fopen("/proc/self/maps", "r"); if (fp) { @@ -3298,21 +3389,20 @@ } // The memory is committed - address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)addr, bytes, pc); - MemTracker::record_virtual_memory_commit((address)addr, bytes, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); return addr; } bool os::release_memory_special(char* base, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); if (rslt == 0) { - MemTracker::record_virtual_memory_uncommit((address)base, bytes); - MemTracker::record_virtual_memory_release((address)base, bytes); + tkr.record((address)base, bytes); return true; } else { + tkr.discard(); return false; } } @@ -4422,7 +4512,7 @@ if (!UseMembar) { address mem_serialize_page = (address) ::mmap(NULL, Linux::page_size(), PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - guarantee( mem_serialize_page != NULL, "mmap Failed for memory serialize page"); + guarantee( mem_serialize_page != MAP_FAILED, "mmap Failed for memory serialize page"); os::set_memory_serialize_page( mem_serialize_page ); #ifndef PRODUCT
--- a/src/os/linux/vm/os_linux.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/linux/vm/os_linux.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,6 +76,10 @@ static julong physical_memory() { return _physical_memory; } static void initialize_system_info(); + static int commit_memory_impl(char* addr, size_t bytes, bool exec); + static int commit_memory_impl(char* addr, size_t bytes, + size_t alignment_hint, bool exec); + static void set_glibc_version(const char *s) { _glibc_version = s; } static void set_libpthread_version(const char *s) { _libpthread_version = s; }
--- a/src/os/linux/vm/perfMemory_linux.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/linux/vm/perfMemory_linux.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ } // commit memory - if (!os::commit_memory(mapAddress, size)) { + if (!os::commit_memory(mapAddress, size, !ExecMem)) { if (PrintMiscellaneous && Verbose) { warning("Could not commit PerfData memory\n"); } @@ -755,8 +755,7 @@ (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); return mapAddress; } @@ -918,8 +917,7 @@ } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); *addr = mapAddress; *sizep = size;
--- a/src/os/solaris/vm/os_solaris.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/solaris/vm/os_solaris.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -2808,7 +2808,42 @@ return page_size; } -bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) { +static bool recoverable_mmap_error(int err) { + // See if the error is one we can let the caller handle. This + // list of errno values comes from the Solaris mmap(2) man page. + switch (err) { + case EBADF: + case EINVAL: + case ENOTSUP: + // let the caller deal with these errors + return true; + + default: + // Any remaining errors on this OS can cause our reserved mapping + // to be lost. That can cause confusion where different data + // structures think they have the same memory mapped. The worst + // scenario is if both the VM and a library think they have the + // same memory mapped. + return false; + } +} + +static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (errno=%d)", addr, bytes, exec, + strerror(err), err); +} + +static void warn_fail_commit_memory(char* addr, size_t bytes, + size_t alignment_hint, bool exec, + int err) { + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, bytes, + alignment_hint, exec, strerror(err), err); +} + +int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) { int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; size_t size = bytes; char *res = Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot); @@ -2816,14 +2851,38 @@ if (UseNUMAInterleaving) { numa_make_global(addr, bytes); } - return true; - } - return false; -} - -bool os::pd_commit_memory(char* addr, size_t bytes, size_t alignment_hint, - bool exec) { - if (commit_memory(addr, bytes, exec)) { + return 0; + } + + int err = errno; // save errno from mmap() call in mmap_chunk() + + if (!recoverable_mmap_error(err)) { + warn_fail_commit_memory(addr, bytes, exec, err); + vm_exit_out_of_memory(bytes, "committing reserved memory."); + } + + return err; +} + +bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) { + return Solaris::commit_memory_impl(addr, bytes, exec) == 0; +} + +void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + int err = os::Solaris::commit_memory_impl(addr, bytes, exec); + if (err != 0) { + // the caller wants all commit errors to exit with the specified mesg: + warn_fail_commit_memory(addr, bytes, exec, err); + vm_exit_out_of_memory(bytes, mesg); + } +} + +int os::Solaris::commit_memory_impl(char* addr, size_t bytes, + size_t alignment_hint, bool exec) { + int err = Solaris::commit_memory_impl(addr, bytes, exec); + if (err == 0) { if (UseMPSS && alignment_hint > (size_t)vm_page_size()) { // If the large page size has been set and the VM // is using large pages, use the large page size @@ -2845,9 +2904,25 @@ // Since this is a hint, ignore any failures. (void)Solaris::set_mpss_range(addr, bytes, page_size); } - return true; - } - return false; + } + return err; +} + +bool os::pd_commit_memory(char* addr, size_t bytes, size_t alignment_hint, + bool exec) { + return Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec) == 0; +} + +void os::pd_commit_memory_or_exit(char* addr, size_t bytes, + size_t alignment_hint, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + int err = os::Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec); + if (err != 0) { + // the caller wants all commit errors to exit with the specified mesg: + warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err); + vm_exit_out_of_memory(bytes, mesg); + } } // Uncommit the pages in a specified region. @@ -2859,7 +2934,7 @@ } bool os::pd_create_stack_guard_pages(char* addr, size_t size) { - return os::commit_memory(addr, size); + return os::commit_memory(addr, size, !ExecMem); } bool os::remove_stack_guard_pages(char* addr, size_t size) { @@ -3481,21 +3556,20 @@ } // The memory is committed - address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)retAddr, size, pc); - MemTracker::record_virtual_memory_commit((address)retAddr, size, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)retAddr, size, mtNone, CURRENT_PC); return retAddr; } bool os::release_memory_special(char* base, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); if (rslt == 0) { - MemTracker::record_virtual_memory_uncommit((address)base, bytes); - MemTracker::record_virtual_memory_release((address)base, bytes); + tkr.record((address)base, bytes); return true; } else { + tkr.discard(); return false; } }
--- a/src/os/solaris/vm/os_solaris.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/solaris/vm/os_solaris.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,6 +168,9 @@ static int _dev_zero_fd; static int get_dev_zero_fd() { return _dev_zero_fd; } static void set_dev_zero_fd(int fd) { _dev_zero_fd = fd; } + static int commit_memory_impl(char* addr, size_t bytes, bool exec); + static int commit_memory_impl(char* addr, size_t bytes, + size_t alignment_hint, bool exec); static char* mmap_chunk(char *addr, size_t size, int flags, int prot); static char* anon_mmap(char* requested_addr, size_t bytes, size_t alignment_hint, bool fixed); static bool mpss_sanity_check(bool warn, size_t * page_size);
--- a/src/os/solaris/vm/perfMemory_solaris.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ } // commit memory - if (!os::commit_memory(mapAddress, size)) { + if (!os::commit_memory(mapAddress, size, !ExecMem)) { if (PrintMiscellaneous && Verbose) { warning("Could not commit PerfData memory\n"); } @@ -770,8 +770,7 @@ (void)::memset((void*) mapAddress, 0, size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); return mapAddress; } @@ -933,8 +932,7 @@ } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); *addr = mapAddress; *sizep = size;
--- a/src/os/windows/vm/os_windows.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/windows/vm/os_windows.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -2426,7 +2426,7 @@ addr = (address)((uintptr_t)addr & (~((uintptr_t)os::vm_page_size() - (uintptr_t)1))); os::commit_memory((char *)addr, thread->stack_base() - addr, - false ); + !ExecMem); return EXCEPTION_CONTINUE_EXECUTION; } else @@ -2809,7 +2809,7 @@ PAGE_READWRITE); // If reservation failed, return NULL if (p_buf == NULL) return NULL; - MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, mtNone, CALLER_PC); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -2875,7 +2875,7 @@ // need to create a dummy 'reserve' record to match // the release. MemTracker::record_virtual_memory_reserve((address)p_buf, - bytes_to_release, CALLER_PC); + bytes_to_release, mtNone, CALLER_PC); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -2895,9 +2895,10 @@ // Although the memory is allocated individually, it is returned as one. // NMT records it as one block. address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, pc); if ((flags & MEM_COMMIT) != 0) { - MemTracker::record_virtual_memory_commit((address)p_buf, bytes, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, mtNone, pc); + } else { + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, mtNone, pc); } // made it this far, success @@ -3092,8 +3093,7 @@ char * res = (char *)VirtualAlloc(NULL, bytes, flag, prot); if (res != NULL) { address pc = CALLER_PC; - MemTracker::record_virtual_memory_reserve((address)res, bytes, pc); - MemTracker::record_virtual_memory_commit((address)res, bytes, pc); + MemTracker::record_virtual_memory_reserve_and_commit((address)res, bytes, mtNone, pc); } return res; @@ -3102,14 +3102,21 @@ bool os::release_memory_special(char* base, size_t bytes) { assert(base != NULL, "Sanity check"); - // Memory allocated via reserve_memory_special() is committed - MemTracker::record_virtual_memory_uncommit((address)base, bytes); return release_memory(base, bytes); } void os::print_statistics() { } +static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec) { + int err = os::get_last_error(); + char buf[256]; + size_t buf_len = os::lasterror(buf, sizeof(buf)); + warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT + ", %d) failed; error='%s' (DOS error/errno=%d)", addr, bytes, + exec, buf_len != 0 ? buf : "<no_error_string>", err); +} + bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) { if (bytes == 0) { // Don't bother the OS with noops. @@ -3124,11 +3131,17 @@ // is always within a reserve covered by a single VirtualAlloc // in that case we can just do a single commit for the requested size if (!UseNUMAInterleaving) { - if (VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) == NULL) return false; + if (VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) == NULL) { + NOT_PRODUCT(warn_fail_commit_memory(addr, bytes, exec);) + return false; + } if (exec) { DWORD oldprot; // Windows doc says to use VirtualProtect to get execute permissions - if (!VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot)) return false; + if (!VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot)) { + NOT_PRODUCT(warn_fail_commit_memory(addr, bytes, exec);) + return false; + } } return true; } else { @@ -3143,12 +3156,20 @@ MEMORY_BASIC_INFORMATION alloc_info; VirtualQuery(next_alloc_addr, &alloc_info, sizeof(alloc_info)); size_t bytes_to_rq = MIN2(bytes_remaining, (size_t)alloc_info.RegionSize); - if (VirtualAlloc(next_alloc_addr, bytes_to_rq, MEM_COMMIT, PAGE_READWRITE) == NULL) + if (VirtualAlloc(next_alloc_addr, bytes_to_rq, MEM_COMMIT, + PAGE_READWRITE) == NULL) { + NOT_PRODUCT(warn_fail_commit_memory(next_alloc_addr, bytes_to_rq, + exec);) return false; + } if (exec) { DWORD oldprot; - if (!VirtualProtect(next_alloc_addr, bytes_to_rq, PAGE_EXECUTE_READWRITE, &oldprot)) + if (!VirtualProtect(next_alloc_addr, bytes_to_rq, + PAGE_EXECUTE_READWRITE, &oldprot)) { + NOT_PRODUCT(warn_fail_commit_memory(next_alloc_addr, bytes_to_rq, + exec);) return false; + } } bytes_remaining -= bytes_to_rq; next_alloc_addr += bytes_to_rq; @@ -3160,7 +3181,24 @@ bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint, bool exec) { - return commit_memory(addr, size, exec); + // alignment_hint is ignored on this OS + return pd_commit_memory(addr, size, exec); +} + +void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, + const char* mesg) { + assert(mesg != NULL, "mesg must be specified"); + if (!pd_commit_memory(addr, size, exec)) { + warn_fail_commit_memory(addr, size, exec); + vm_exit_out_of_memory(size, mesg); + } +} + +void os::pd_commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, bool exec, + const char* mesg) { + // alignment_hint is ignored on this OS + pd_commit_memory_or_exit(addr, size, exec, mesg); } bool os::pd_uncommit_memory(char* addr, size_t bytes) { @@ -3178,7 +3216,7 @@ } bool os::pd_create_stack_guard_pages(char* addr, size_t size) { - return os::commit_memory(addr, size); + return os::commit_memory(addr, size, !ExecMem); } bool os::remove_stack_guard_pages(char* addr, size_t size) { @@ -3202,8 +3240,9 @@ // Strange enough, but on Win32 one can change protection only for committed // memory, not a big deal anyway, as bytes less or equal than 64K - if (!is_committed && !commit_memory(addr, bytes, prot == MEM_PROT_RWX)) { - fatal("cannot commit protection page"); + if (!is_committed) { + commit_memory_or_exit(addr, bytes, prot == MEM_PROT_RWX, + "cannot commit protection page"); } // One cannot use os::guard_memory() here, as on Win32 guard page // have different (one-shot) semantics, from MSDN on PAGE_GUARD:
--- a/src/os/windows/vm/perfMemory_windows.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/os/windows/vm/perfMemory_windows.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ } // commit memory - if (!os::commit_memory(mapAddress, size)) { + if (!os::commit_memory(mapAddress, size, !ExecMem)) { if (PrintMiscellaneous && Verbose) { warning("Could not commit PerfData memory\n"); } @@ -1498,8 +1498,7 @@ (void)memset(mapAddress, '\0', size); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); return (char*) mapAddress; } @@ -1678,8 +1677,7 @@ } // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC); - MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal); + MemTracker::record_virtual_memory_reserve((address)mapAddress, size, mtInternal, CURRENT_PC); *addrp = (char*)mapAddress; @@ -1833,9 +1831,10 @@ return; } + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); remove_file_mapping(addr); // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_release((address)addr, bytes); + tkr.record((address)addr, bytes); } char* PerfMemory::backing_store_filename() {
--- a/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -649,11 +649,9 @@ if(new_start_aligned < new_end_for_commit) { MemRegion new_committed = MemRegion(new_start_aligned, new_end_for_commit); - if (!os::commit_memory((char*)new_committed.start(), - new_committed.byte_size())) { - vm_exit_out_of_memory(new_committed.byte_size(), - "card table expansion"); - } + os::commit_memory_or_exit((char*)new_committed.start(), + new_committed.byte_size(), !ExecMem, + "card table expansion"); } result = true; } else if (new_start_aligned > cur_committed.start()) {
--- a/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -55,18 +55,18 @@ const size_t raw_bytes = words * sizeof(idx_t); const size_t page_sz = os::page_size_for_region(raw_bytes, raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); - const size_t bytes = align_size_up(raw_bytes, MAX2(page_sz, granularity)); + _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity)); const size_t rs_align = page_sz == (size_t) os::vm_page_size() ? 0 : MAX2(page_sz, granularity); - ReservedSpace rs(bytes, rs_align, rs_align > 0); + ReservedSpace rs(_reserved_byte_size, rs_align, rs_align > 0); os::trace_page_sizes("par bitmap", raw_bytes, raw_bytes, page_sz, rs.base(), rs.size()); MemTracker::record_virtual_memory_type((address)rs.base(), mtGC); _virtual_space = new PSVirtualSpace(rs, page_sz); - if (_virtual_space != NULL && _virtual_space->expand_by(bytes)) { + if (_virtual_space != NULL && _virtual_space->expand_by(_reserved_byte_size)) { _region_start = covered_region.start(); _region_size = covered_region.word_size(); idx_t* map = (idx_t*)_virtual_space->reserved_low_addr();
--- a/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/parMarkBitMap.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -141,6 +141,8 @@ inline size_t region_size() const; inline size_t size() const; + size_t reserved_byte_size() const { return _reserved_byte_size; } + // Convert a heap address to/from a bit index. inline idx_t addr_to_bit(HeapWord* addr) const; inline HeapWord* bit_to_addr(idx_t bit) const; @@ -191,6 +193,7 @@ BitMap _beg_bits; BitMap _end_bits; PSVirtualSpace* _virtual_space; + size_t _reserved_byte_size; #ifndef PRODUCT size_t _cas_tries; @@ -205,6 +208,7 @@ { _region_start = 0; _virtual_space = 0; + _reserved_byte_size = 0; } inline ParMarkBitMap::ParMarkBitMap(MemRegion covered_region):
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -389,6 +389,7 @@ _region_start = 0; _region_vspace = 0; + _reserved_byte_size = 0; _region_data = 0; _region_count = 0; @@ -418,11 +419,11 @@ const size_t raw_bytes = count * element_size; const size_t page_sz = os::page_size_for_region(raw_bytes, raw_bytes, 10); const size_t granularity = os::vm_allocation_granularity(); - const size_t bytes = align_size_up(raw_bytes, MAX2(page_sz, granularity)); + _reserved_byte_size = align_size_up(raw_bytes, MAX2(page_sz, granularity)); const size_t rs_align = page_sz == (size_t) os::vm_page_size() ? 0 : MAX2(page_sz, granularity); - ReservedSpace rs(bytes, rs_align, rs_align > 0); + ReservedSpace rs(_reserved_byte_size, rs_align, rs_align > 0); os::trace_page_sizes("par compact", raw_bytes, raw_bytes, page_sz, rs.base(), rs.size()); @@ -430,7 +431,7 @@ PSVirtualSpace* vspace = new PSVirtualSpace(rs, page_sz); if (vspace != 0) { - if (vspace->expand_by(bytes)) { + if (vspace->expand_by(_reserved_byte_size)) { return vspace; } delete vspace; @@ -893,14 +894,18 @@ initialize_dead_wood_limiter(); if (!_mark_bitmap.initialize(mr)) { - vm_shutdown_during_initialization("Unable to allocate bit map for " - "parallel garbage collection for the requested heap size."); + vm_shutdown_during_initialization( + err_msg("Unable to allocate " SIZE_FORMAT "KB bitmaps for parallel " + "garbage collection for the requested " SIZE_FORMAT "KB heap.", + _mark_bitmap.reserved_byte_size()/K, mr.byte_size()/K)); return false; } if (!_summary_data.initialize(mr)) { - vm_shutdown_during_initialization("Unable to allocate tables for " - "parallel garbage collection for the requested heap size."); + vm_shutdown_during_initialization( + err_msg("Unable to allocate " SIZE_FORMAT "KB card tables for parallel " + "garbage collection for the requested " SIZE_FORMAT "KB heap.", + _summary_data.reserved_byte_size()/K, mr.byte_size()/K)); return false; }
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -387,6 +387,7 @@ bool initialize(MemRegion covered_region); size_t region_count() const { return _region_count; } + size_t reserved_byte_size() const { return _reserved_byte_size; } // Convert region indices to/from RegionData pointers. inline RegionData* region(size_t region_idx) const; @@ -478,6 +479,7 @@ #endif // #ifdef ASSERT PSVirtualSpace* _region_vspace; + size_t _reserved_byte_size; RegionData* _region_data; size_t _region_count;
--- a/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psVirtualspace.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,8 @@ } char* const base_addr = committed_high_addr(); - bool result = special() || os::commit_memory(base_addr, bytes, alignment()); + bool result = special() || + os::commit_memory(base_addr, bytes, alignment(), !ExecMem); if (result) { _committed_high_addr += bytes; } @@ -154,7 +155,7 @@ if (tmp_bytes > 0) { char* const commit_base = committed_high_addr(); if (other_space->special() || - os::commit_memory(commit_base, tmp_bytes, alignment())) { + os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { // Reduce the reserved region in the other space. other_space->set_reserved(other_space->reserved_low_addr() + tmp_bytes, other_space->reserved_high_addr(), @@ -269,7 +270,8 @@ } char* const base_addr = committed_low_addr() - bytes; - bool result = special() || os::commit_memory(base_addr, bytes, alignment()); + bool result = special() || + os::commit_memory(base_addr, bytes, alignment(), !ExecMem); if (result) { _committed_low_addr -= bytes; } @@ -322,7 +324,7 @@ if (tmp_bytes > 0) { char* const commit_base = committed_low_addr() - tmp_bytes; if (other_space->special() || - os::commit_memory(commit_base, tmp_bytes, alignment())) { + os::commit_memory(commit_base, tmp_bytes, alignment(), !ExecMem)) { // Reduce the reserved region in the other space. other_space->set_reserved(other_space->reserved_low_addr(), other_space->reserved_high_addr() - tmp_bytes,
--- a/src/share/vm/gc_implementation/shared/gcTrace.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/gcTrace.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -23,13 +23,15 @@ */ #include "precompiled.hpp" +#include "gc_implementation/shared/copyFailedInfo.hpp" #include "gc_implementation/shared/gcHeapSummary.hpp" #include "gc_implementation/shared/gcTimer.hpp" #include "gc_implementation/shared/gcTrace.hpp" -#include "gc_implementation/shared/copyFailedInfo.hpp" +#include "gc_implementation/shared/objectCountEventSender.hpp" #include "memory/heapInspection.hpp" #include "memory/iterator.hpp" #include "memory/referenceProcessorStats.hpp" +#include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" #ifndef SERIALGC @@ -39,7 +41,7 @@ #define assert_unset_gc_id() assert(_shared_gc_info.id() == SharedGCInfo::UNSET_GCID, "GC already started?") #define assert_set_gc_id() assert(_shared_gc_info.id() != SharedGCInfo::UNSET_GCID, "GC not started?") -static jlong GCTracer_next_gc_id = 0; +static GCId GCTracer_next_gc_id = 0; static GCId create_new_gc_id() { return GCTracer_next_gc_id++; } @@ -91,35 +93,60 @@ send_reference_stats_event(REF_PHANTOM, rps.phantom_count()); } -void ObjectCountEventSenderClosure::do_cinfo(KlassInfoEntry* entry) { - if (should_send_event(entry)) { - send_event(entry); +class ObjectCountEventSenderClosure : public KlassInfoClosure { + const GCId _gc_id; + const double _size_threshold_percentage; + const size_t _total_size_in_words; + const jlong _timestamp; + + public: + ObjectCountEventSenderClosure(GCId gc_id, size_t total_size_in_words, jlong timestamp) : + _gc_id(gc_id), + _size_threshold_percentage(ObjectCountCutOffPercent / 100), + _total_size_in_words(total_size_in_words), + _timestamp(timestamp) + {} + + virtual void do_cinfo(KlassInfoEntry* entry) { + if (should_send_event(entry)) { + ObjectCountEventSender::send(entry, _gc_id, _timestamp); + } } -} - -void ObjectCountEventSenderClosure::send_event(KlassInfoEntry* entry) { - _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(), - entry->words() * BytesPerWord); -} -bool ObjectCountEventSenderClosure::should_send_event(KlassInfoEntry* entry) const { - double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; - return percentage_of_heap > _size_threshold_percentage; -} + private: + bool should_send_event(const KlassInfoEntry* entry) const { + double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; + return percentage_of_heap >= _size_threshold_percentage; + } +}; + +class ObjectCountFilter : public BoolObjectClosure { + BoolObjectClosure* _is_alive; -bool ObjectCountFilter::do_object_b(oop obj) { - bool is_alive = _is_alive == NULL? true : _is_alive->do_object_b(obj); - return is_alive && is_externally_visible_klass(obj->klass()); -} + public: + ObjectCountFilter(BoolObjectClosure* is_alive) : _is_alive(is_alive) { + assert(is_alive != NULL, "Must supply function to check liveness"); + } + + bool do_object_b(oop obj) { + return _is_alive->do_object_b(obj) && is_externally_visible_klass(obj->klass()); + } -bool ObjectCountFilter::is_externally_visible_klass(klassOop k) const { - // Do not expose internal implementation specific classes - return (k->klass_part()->oop_is_instance() || k->klass_part()->oop_is_array()) && - k != Universe::systemObjArrayKlassObj(); -} + void do_object(oop obj) { ShouldNotReachHere(); } + + private: + bool is_externally_visible_klass(klassOop k) const { + // Do not expose internal implementation specific classes + return (k->klass_part()->oop_is_instance() || k->klass_part()->oop_is_array()) && + k != Universe::systemObjArrayKlassObj(); + } +}; void GCTracer::report_object_count_after_gc(BoolObjectClosure *is_alive_cl) { - if (should_send_object_count_after_gc_event()) { + assert_set_gc_id(); + assert(is_alive_cl != NULL, "Must supply function to check liveness"); + + if (ObjectCountEventSender::should_send_event()) { ResourceMark rm; KlassInfoTable cit(HeapInspection::start_of_perm_gen()); @@ -127,7 +154,8 @@ ObjectCountFilter object_filter(is_alive_cl); HeapInspection::populate_table(&cit, false, &object_filter); - ObjectCountEventSenderClosure event_sender(this, cit.size_of_instances_in_words()); + jlong timestamp = os::elapsed_counter(); + ObjectCountEventSenderClosure event_sender(_shared_gc_info.id(), cit.size_of_instances_in_words(), timestamp); cit.iterate(&event_sender); } }
--- a/src/share/vm/gc_implementation/shared/gcTrace.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/gcTrace.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -30,7 +30,6 @@ #include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/allocation.hpp" -#include "memory/klassInfoClosure.hpp" #include "memory/referenceType.hpp" #ifndef SERIALGC #include "gc_implementation/g1/g1YCTypes.hpp" @@ -112,7 +111,6 @@ #endif // SERIALGC class GCTracer : public ResourceObj { - friend class ObjectCountEventSenderClosure; protected: SharedGCInfo _shared_gc_info; @@ -136,35 +134,6 @@ void send_perm_gen_summary_event(GCWhen::Type when, const PermGenSummary& perm_gen_summary) const; void send_reference_stats_event(ReferenceType type, size_t count) const; void send_phase_events(TimePartitions* time_partitions) const; - void send_object_count_after_gc_event(klassOop klass, jlong count, julong total_size) const; - bool should_send_object_count_after_gc_event() const; -}; - -class ObjectCountEventSenderClosure : public KlassInfoClosure { - GCTracer* _gc_tracer; - const double _size_threshold_percentage; - const size_t _total_size_in_words; - public: - ObjectCountEventSenderClosure(GCTracer* gc_tracer, size_t total_size_in_words) : - _gc_tracer(gc_tracer), - _size_threshold_percentage(ObjectCountCutOffPercent / 100), - _total_size_in_words(total_size_in_words) - {} - virtual void do_cinfo(KlassInfoEntry* entry); - protected: - virtual void send_event(KlassInfoEntry* entry); - private: - bool should_send_event(KlassInfoEntry* entry) const; -}; - -class ObjectCountFilter : public BoolObjectClosure { - BoolObjectClosure* _is_alive; - public: - ObjectCountFilter(BoolObjectClosure* is_alive = NULL) : _is_alive(is_alive) {} - bool do_object_b(oop obj); - void do_object(oop obj) { ShouldNotReachHere(); } - private: - bool is_externally_visible_klass(klassOop k) const; }; class YoungGCTracer : public GCTracer {
--- a/src/share/vm/gc_implementation/shared/gcTraceSend.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -123,25 +123,6 @@ } } -void GCTracer::send_object_count_after_gc_event(klassOop klass, jlong count, julong total_size) const { - EventObjectCountAfterGC e; - if (e.should_commit()) { - e.set_gcId(_shared_gc_info.id()); - e.set_class(klass); - e.set_count(count); - e.set_totalSize(total_size); - e.commit(); - } -} - -bool GCTracer::should_send_object_count_after_gc_event() const { -#if INCLUDE_TRACE - return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId); -#else - return false; -#endif -} - #ifndef SERIALGC void G1NewTracer::send_g1_young_gc_event() { EventGCG1GarbageCollection e(UNTIMED);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/objectCountEventSender.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +#include "precompiled.hpp" +#include "gc_implementation/shared/objectCountEventSender.hpp" +#include "memory/heapInspection.hpp" +#include "trace/tracing.hpp" +#include "utilities/globalDefinitions.hpp" + +void ObjectCountEventSender::send(const KlassInfoEntry* entry, GCId gc_id, jlong timestamp) { + assert(Tracing::is_event_enabled(EventObjectCountAfterGC::eventId), + "Only call this method if the event is enabled"); + + EventObjectCountAfterGC event(UNTIMED); + event.set_gcId(gc_id); + event.set_class(entry->klass()); + event.set_count(entry->count()); + event.set_totalSize(entry->words() * BytesPerWord); + event.set_endtime(timestamp); + event.commit(); +} + +bool ObjectCountEventSender::should_send_event() { +#if INCLUDE_TRACE + return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId); +#else + return false; +#endif +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shared/objectCountEventSender.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OBJECT_COUNT_EVENT_SENDER_HPP +#define SHARE_VM_OBJECT_COUNT_EVENT_SENDER_HPP + +#include "gc_implementation/shared/gcTrace.hpp" +#include "memory/allocation.hpp" + +class KlassInfoEntry; + +class ObjectCountEventSender : public AllStatic { + public: + static void send(const KlassInfoEntry* entry, GCId gc_id, jlong timestamp); + static bool should_send_event(); +}; + +#endif // SHARE_VM_OBJECT_COUNT_EVENT_SENDER
--- a/src/share/vm/memory/allocation.inline.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/memory/allocation.inline.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,10 +128,7 @@ vm_exit_out_of_memory(_size, "Allocator (reserve)"); } - bool success = os::commit_memory(_addr, _size, false /* executable */); - if (!success) { - vm_exit_out_of_memory(_size, "Allocator (commit)"); - } + os::commit_memory_or_exit(_addr, _size, !ExecMem, "Allocator (commit)"); return (E*)_addr; }
--- a/src/share/vm/memory/cardTableModRefBS.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,10 +113,8 @@ jbyte* guard_card = &_byte_map[_guard_index]; uintptr_t guard_page = align_size_down((uintptr_t)guard_card, _page_size); _guard_region = MemRegion((HeapWord*)guard_page, _page_size); - if (!os::commit_memory((char*)guard_page, _page_size, _page_size)) { - // Do better than this for Merlin - vm_exit_out_of_memory(_page_size, "card table last card"); - } + os::commit_memory_or_exit((char*)guard_page, _page_size, _page_size, + !ExecMem, "card table last card"); *guard_card = last_card; @@ -288,12 +286,9 @@ MemRegion(cur_committed.end(), new_end_for_commit); assert(!new_committed.is_empty(), "Region should not be empty here"); - if (!os::commit_memory((char*)new_committed.start(), - new_committed.byte_size(), _page_size)) { - // Do better than this for Merlin - vm_exit_out_of_memory(new_committed.byte_size(), - "card table expansion"); - } + os::commit_memory_or_exit((char*)new_committed.start(), + new_committed.byte_size(), _page_size, + !ExecMem, "card table expansion"); // Use new_end_aligned (as opposed to new_end_for_commit) because // the cur_committed region may include the guard region. } else if (new_end_aligned < cur_committed.end()) {
--- a/src/share/vm/memory/heapInspection.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/memory/heapInspection.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -26,7 +26,6 @@ #define SHARE_VM_MEMORY_HEAPINSPECTION_HPP #include "memory/allocation.inline.hpp" -#include "memory/klassInfoClosure.hpp" #include "oops/oop.inline.hpp" @@ -56,15 +55,21 @@ {} KlassInfoEntry* next() { return _next; } bool is_equal(klassOop k) { return k == _klass; } - klassOop klass() { return _klass; } - long count() { return _instance_count; } + klassOop klass() const { return _klass; } + long count() const { return _instance_count; } void set_count(long ct) { _instance_count = ct; } - size_t words() { return _instance_words; } + size_t words() const { return _instance_words; } void set_words(size_t wds) { _instance_words = wds; } int compare(KlassInfoEntry* e1, KlassInfoEntry* e2); void print_on(outputStream* st) const; }; +class KlassInfoClosure : public StackObj { + public: + // Called for each KlassInfoEntry. + virtual void do_cinfo(KlassInfoEntry* cie) = 0; +}; + class KlassInfoBucket: public CHeapObj<mtInternal> { private: KlassInfoEntry* _list;
--- a/src/share/vm/memory/klassInfoClosure.hpp Wed Jun 12 19:58:20 2013 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP -#define SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP - -class KlassInfoEntry; - -class KlassInfoClosure : public StackObj { - public: - // Called for each KlassInfoEntry. - virtual void do_cinfo(KlassInfoEntry* cie) = 0; -}; - -#endif // SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP
--- a/src/share/vm/prims/whitebox.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/prims/whitebox.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,7 +109,7 @@ WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) - os::commit_memory((char *)(uintptr_t)addr, size); + os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem); MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest); WB_END
--- a/src/share/vm/runtime/os.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/runtime/os.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -603,10 +603,13 @@ #ifndef ASSERT NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); + MemTracker::Tracker tkr = MemTracker::get_realloc_tracker(); void* ptr = ::realloc(memblock, size); if (ptr != NULL) { - MemTracker::record_realloc((address)memblock, (address)ptr, size, memflags, + tkr.record((address)memblock, (address)ptr, size, memflags, caller == 0 ? CALLER_PC : caller); + } else { + tkr.discard(); } return ptr; #else @@ -1398,7 +1401,7 @@ char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { char* result = pd_reserve_memory(bytes, addr, alignment_hint); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); } return result; @@ -1408,7 +1411,7 @@ MEMFLAGS flags) { char* result = pd_reserve_memory(bytes, addr, alignment_hint); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); MemTracker::record_virtual_memory_type((address)result, flags); } @@ -1418,7 +1421,7 @@ char* os::attempt_reserve_memory_at(size_t bytes, char* addr) { char* result = pd_attempt_reserve_memory_at(bytes, addr); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)result, bytes, mtNone, CALLER_PC); } return result; } @@ -1445,18 +1448,36 @@ return res; } +void os::commit_memory_or_exit(char* addr, size_t bytes, bool executable, + const char* mesg) { + pd_commit_memory_or_exit(addr, bytes, executable, mesg); + MemTracker::record_virtual_memory_commit((address)addr, bytes, CALLER_PC); +} + +void os::commit_memory_or_exit(char* addr, size_t size, size_t alignment_hint, + bool executable, const char* mesg) { + os::pd_commit_memory_or_exit(addr, size, alignment_hint, executable, mesg); + MemTracker::record_virtual_memory_commit((address)addr, size, CALLER_PC); +} + bool os::uncommit_memory(char* addr, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); bool res = pd_uncommit_memory(addr, bytes); if (res) { - MemTracker::record_virtual_memory_uncommit((address)addr, bytes); + tkr.record((address)addr, bytes); + } else { + tkr.discard(); } return res; } bool os::release_memory(char* addr, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); bool res = pd_release_memory(addr, bytes); if (res) { - MemTracker::record_virtual_memory_release((address)addr, bytes); + tkr.record((address)addr, bytes); + } else { + tkr.discard(); } return res; } @@ -1473,8 +1494,7 @@ bool allow_exec) { char* result = pd_map_memory(fd, file_name, file_offset, addr, bytes, read_only, allow_exec); if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); - MemTracker::record_virtual_memory_commit((address)result, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, mtNone, CALLER_PC); } return result; } @@ -1487,10 +1507,12 @@ } bool os::unmap_memory(char *addr, size_t bytes) { + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); bool result = pd_unmap_memory(addr, bytes); if (result) { - MemTracker::record_virtual_memory_uncommit((address)addr, bytes); - MemTracker::record_virtual_memory_release((address)addr, bytes); + tkr.record((address)addr, bytes); + } else { + tkr.discard(); } return result; }
--- a/src/share/vm/runtime/os.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/runtime/os.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,6 +78,10 @@ CriticalPriority = 11 // Critical thread priority }; +// Executable parameter flag for os::commit_memory() and +// os::commit_memory_or_exit(). +const bool ExecMem = true; + // Typedef for structured exception handling support typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread); @@ -104,9 +108,16 @@ static char* pd_attempt_reserve_memory_at(size_t bytes, char* addr); static void pd_split_reserved_memory(char *base, size_t size, size_t split, bool realloc); - static bool pd_commit_memory(char* addr, size_t bytes, bool executable = false); + static bool pd_commit_memory(char* addr, size_t bytes, bool executable); static bool pd_commit_memory(char* addr, size_t size, size_t alignment_hint, - bool executable = false); + bool executable); + // Same as pd_commit_memory() that either succeeds or calls + // vm_exit_out_of_memory() with the specified mesg. + static void pd_commit_memory_or_exit(char* addr, size_t bytes, + bool executable, const char* mesg); + static void pd_commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, + bool executable, const char* mesg); static bool pd_uncommit_memory(char* addr, size_t bytes); static bool pd_release_memory(char* addr, size_t bytes); @@ -261,9 +272,16 @@ static char* attempt_reserve_memory_at(size_t bytes, char* addr); static void split_reserved_memory(char *base, size_t size, size_t split, bool realloc); - static bool commit_memory(char* addr, size_t bytes, bool executable = false); + static bool commit_memory(char* addr, size_t bytes, bool executable); static bool commit_memory(char* addr, size_t size, size_t alignment_hint, - bool executable = false); + bool executable); + // Same as commit_memory() that either succeeds or calls + // vm_exit_out_of_memory() with the specified mesg. + static void commit_memory_or_exit(char* addr, size_t bytes, + bool executable, const char* mesg); + static void commit_memory_or_exit(char* addr, size_t size, + size_t alignment_hint, + bool executable, const char* mesg); static bool uncommit_memory(char* addr, size_t bytes); static bool release_memory(char* addr, size_t bytes); static bool can_release_partial_region();
--- a/src/share/vm/runtime/virtualspace.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/runtime/virtualspace.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -746,11 +746,13 @@ lower_high() + lower_needs <= lower_high_boundary(), "must not expand beyond region"); if (!os::commit_memory(lower_high(), lower_needs, _executable)) { - debug_only(warning("os::commit_memory failed")); + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", lower_needs=" SIZE_FORMAT ", %d) failed", + lower_high(), lower_needs, _executable);) return false; } else { _lower_high += lower_needs; - } + } } if (middle_needs > 0) { assert(lower_high_boundary() <= middle_high() && @@ -758,7 +760,10 @@ "must not expand beyond region"); if (!os::commit_memory(middle_high(), middle_needs, middle_alignment(), _executable)) { - debug_only(warning("os::commit_memory failed")); + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", middle_needs=" SIZE_FORMAT ", " SIZE_FORMAT + ", %d) failed", middle_high(), middle_needs, + middle_alignment(), _executable);) return false; } _middle_high += middle_needs; @@ -768,7 +773,9 @@ upper_high() + upper_needs <= upper_high_boundary(), "must not expand beyond region"); if (!os::commit_memory(upper_high(), upper_needs, _executable)) { - debug_only(warning("os::commit_memory failed")); + debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT + ", upper_needs=" SIZE_FORMAT ", %d) failed", + upper_high(), upper_needs, _executable);) return false; } else { _upper_high += upper_needs;
--- a/src/share/vm/services/memPtr.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/services/memPtr.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -457,9 +457,8 @@ public: SeqMemPointerRecord(): _seq(0){ } - SeqMemPointerRecord(address addr, MEMFLAGS flags, size_t size) - : MemPointerRecord(addr, flags, size) { - _seq = SequenceGenerator::next(); + SeqMemPointerRecord(address addr, MEMFLAGS flags, size_t size, jint seq) + : MemPointerRecord(addr, flags, size), _seq(seq) { } SeqMemPointerRecord(const SeqMemPointerRecord& copy_from) @@ -488,8 +487,8 @@ SeqMemPointerRecordEx(): _seq(0) { } SeqMemPointerRecordEx(address addr, MEMFLAGS flags, size_t size, - address pc): MemPointerRecordEx(addr, flags, size, pc) { - _seq = SequenceGenerator::next(); + jint seq, address pc): + MemPointerRecordEx(addr, flags, size, pc), _seq(seq) { } SeqMemPointerRecordEx(const SeqMemPointerRecordEx& copy_from)
--- a/src/share/vm/services/memRecorder.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/services/memRecorder.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -69,10 +69,11 @@ if (_pointer_records != NULL) { // recode itself + address pc = CURRENT_PC; record((address)this, (MemPointerRecord::malloc_tag()|mtNMT|otNMTRecorder), - sizeof(MemRecorder), CALLER_PC); + sizeof(MemRecorder), SequenceGenerator::next(), pc); record((address)_pointer_records, (MemPointerRecord::malloc_tag()|mtNMT|otNMTRecorder), - _pointer_records->instance_size(),CURRENT_PC); + _pointer_records->instance_size(), SequenceGenerator::next(), pc); } } @@ -116,7 +117,8 @@ } } -bool MemRecorder::record(address p, MEMFLAGS flags, size_t size, address pc) { +bool MemRecorder::record(address p, MEMFLAGS flags, size_t size, jint seq, address pc) { + assert(seq > 0, "No sequence number"); #ifdef ASSERT if (MemPointerRecord::is_virtual_memory_record(flags)) { assert((flags & MemPointerRecord::tag_masks) != 0, "bad virtual memory record"); @@ -133,11 +135,11 @@ #endif if (MemTracker::track_callsite()) { - SeqMemPointerRecordEx ap(p, flags, size, pc); + SeqMemPointerRecordEx ap(p, flags, size, seq, pc); debug_only(check_dup_seq(ap.seq());) return _pointer_records->append(&ap); } else { - SeqMemPointerRecord ap(p, flags, size); + SeqMemPointerRecord ap(p, flags, size, seq); debug_only(check_dup_seq(ap.seq());) return _pointer_records->append(&ap); }
--- a/src/share/vm/services/memRecorder.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/services/memRecorder.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -220,7 +220,7 @@ ~MemRecorder(); // record a memory operation - bool record(address addr, MEMFLAGS flags, size_t size, address caller_pc = 0); + bool record(address addr, MEMFLAGS flags, size_t size, jint seq, address caller_pc = 0); // linked list support inline void set_next(MemRecorder* rec) {
--- a/src/share/vm/services/memReporter.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/services/memReporter.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -190,17 +190,18 @@ while (cur_malloc_callsite != NULL || prev_malloc_callsite != NULL) { if (prev_malloc_callsite == NULL || cur_malloc_callsite->addr() < prev_malloc_callsite->addr()) { + // this is a new callsite _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(), amount_in_current_scale(cur_malloc_callsite->amount()), cur_malloc_callsite->count(), diff_in_current_scale(cur_malloc_callsite->amount(), 0), diff(cur_malloc_callsite->count(), 0)); cur_malloc_callsite = (MallocCallsitePointer*)cur_malloc_itr.next(); - } else if (prev_malloc_callsite == NULL || + } else if (cur_malloc_callsite == NULL || cur_malloc_callsite->addr() > prev_malloc_callsite->addr()) { - _outputer.diff_malloc_callsite(cur_malloc_callsite->addr(), - amount_in_current_scale(prev_malloc_callsite->amount()), - prev_malloc_callsite->count(), + // this callsite is already gone + _outputer.diff_malloc_callsite(prev_malloc_callsite->addr(), + amount_in_current_scale(0), 0, diff_in_current_scale(0, prev_malloc_callsite->amount()), diff(0, prev_malloc_callsite->count())); prev_malloc_callsite = (MallocCallsitePointer*)prev_malloc_itr.next(); @@ -222,6 +223,7 @@ VMCallsitePointer* prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.current(); while (cur_vm_callsite != NULL || prev_vm_callsite != NULL) { if (prev_vm_callsite == NULL || cur_vm_callsite->addr() < prev_vm_callsite->addr()) { + // this is a new callsite _outputer.diff_virtual_memory_callsite(cur_vm_callsite->addr(), amount_in_current_scale(cur_vm_callsite->reserved_amount()), amount_in_current_scale(cur_vm_callsite->committed_amount()), @@ -229,9 +231,10 @@ diff_in_current_scale(cur_vm_callsite->committed_amount(), 0)); cur_vm_callsite = (VMCallsitePointer*)cur_vm_itr.next(); } else if (cur_vm_callsite == NULL || cur_vm_callsite->addr() > prev_vm_callsite->addr()) { + // this callsite is already gone _outputer.diff_virtual_memory_callsite(prev_vm_callsite->addr(), - amount_in_current_scale(prev_vm_callsite->reserved_amount()), - amount_in_current_scale(prev_vm_callsite->committed_amount()), + amount_in_current_scale(0), + amount_in_current_scale(0), diff_in_current_scale(0, prev_vm_callsite->reserved_amount()), diff_in_current_scale(0, prev_vm_callsite->committed_amount())); prev_vm_callsite = (VMCallsitePointer*)prev_vm_itr.next();
--- a/src/share/vm/services/memTracker.cpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/services/memTracker.cpp Thu Jun 13 10:26:22 2013 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" + #include "oops/instanceKlass.hpp" #include "runtime/atomic.hpp" #include "runtime/interfaceSupport.hpp" @@ -36,6 +37,7 @@ #include "utilities/decoder.hpp" #include "utilities/globalDefinitions.hpp" + bool NMT_track_callsite = false; // walk all 'known' threads at NMT sync point, and collect their recorders @@ -68,6 +70,7 @@ volatile jint MemTracker::_pooled_recorder_count = 0; volatile unsigned long MemTracker::_processing_generation = 0; volatile bool MemTracker::_worker_thread_idle = false; +volatile jint MemTracker::_pending_op_count = 0; volatile bool MemTracker::_slowdown_calling_thread = false; debug_only(intx MemTracker::_main_thread_tid = 0;) NOT_PRODUCT(volatile jint MemTracker::_pending_recorder_count = 0;) @@ -328,92 +331,14 @@ Atomic::inc(&_pooled_recorder_count); } -/* - * This is the most important method in whole nmt implementation. - * - * Create a memory record. - * 1. When nmt is in single-threaded bootstrapping mode, no lock is needed as VM - * still in single thread mode. - * 2. For all threads other than JavaThread, ThreadCritical is needed - * to write to recorders to global recorder. - * 3. For JavaThreads that are not longer visible by safepoint, also - * need to take ThreadCritical and records are written to global - * recorders, since these threads are NOT walked by Threads.do_thread(). - * 4. JavaThreads that are running in native state, have to transition - * to VM state before writing to per-thread recorders. - * 5. JavaThreads that are running in VM state do not need any lock and - * records are written to per-thread recorders. - * 6. For a thread has yet to attach VM 'Thread', they need to take - * ThreadCritical to write to global recorder. - * - * Important note: - * NO LOCK should be taken inside ThreadCritical lock !!! - */ -void MemTracker::create_memory_record(address addr, MEMFLAGS flags, - size_t size, address pc, Thread* thread) { - assert(addr != NULL, "Sanity check"); - if (!shutdown_in_progress()) { - // single thread, we just write records direct to global recorder,' - // with any lock - if (_state == NMT_bootstrapping_single_thread) { - assert(_main_thread_tid == os::current_thread_id(), "wrong thread"); - thread = NULL; - } else { - if (thread == NULL) { - // don't use Thread::current(), since it is possible that - // the calling thread has yet to attach to VM 'Thread', - // which will result assertion failure - thread = ThreadLocalStorage::thread(); - } - } - - if (thread != NULL) { - // slow down all calling threads except NMT worker thread, so it - // can catch up. - if (_slowdown_calling_thread && thread != _worker_thread) { - os::yield_all(); - } - - if (thread->is_Java_thread() && ((JavaThread*)thread)->is_safepoint_visible()) { - JavaThread* java_thread = (JavaThread*)thread; - JavaThreadState state = java_thread->thread_state(); - if (SafepointSynchronize::safepoint_safe(java_thread, state)) { - // JavaThreads that are safepoint safe, can run through safepoint, - // so ThreadCritical is needed to ensure no threads at safepoint create - // new records while the records are being gathered and the sequence number is changing - ThreadCritical tc; - create_record_in_recorder(addr, flags, size, pc, java_thread); - } else { - create_record_in_recorder(addr, flags, size, pc, java_thread); - } - } else { - // other threads, such as worker and watcher threads, etc. need to - // take ThreadCritical to write to global recorder - ThreadCritical tc; - create_record_in_recorder(addr, flags, size, pc, NULL); - } - } else { - if (_state == NMT_bootstrapping_single_thread) { - // single thread, no lock needed - create_record_in_recorder(addr, flags, size, pc, NULL); - } else { - // for thread has yet to attach VM 'Thread', we can not use VM mutex. - // use native thread critical instead - ThreadCritical tc; - create_record_in_recorder(addr, flags, size, pc, NULL); - } - } - } -} - // write a record to proper recorder. No lock can be taken from this method // down. -void MemTracker::create_record_in_recorder(address addr, MEMFLAGS flags, - size_t size, address pc, JavaThread* thread) { +void MemTracker::write_tracking_record(address addr, MEMFLAGS flags, + size_t size, jint seq, address pc, JavaThread* thread) { MemRecorder* rc = get_thread_recorder(thread); if (rc != NULL) { - rc->record(addr, flags, size, pc); + rc->record(addr, flags, size, seq, pc); } } @@ -478,13 +403,15 @@ return; } } - _sync_point_skip_count = 0; { // This method is running at safepoint, with ThreadCritical lock, // it should guarantee that NMT is fully sync-ed. ThreadCritical tc; + // We can NOT execute NMT sync-point if there are pending tracking ops. + if (_pending_op_count == 0) { SequenceGenerator::reset(); + _sync_point_skip_count = 0; // walk all JavaThreads to collect recorders SyncThreadRecorderClosure stc; @@ -509,8 +436,10 @@ if (_worker_thread != NULL) { _worker_thread->at_sync_point(pending_recorders, instanceKlass::number_of_instance_classes()); } - assert(SequenceGenerator::peek() == 1, "Should not have memory activities during sync-point"); + } else { + _sync_point_skip_count ++; + } } } @@ -699,3 +628,243 @@ } #endif + +// Tracker Implementation + +/* + * Create a tracker. + * This is a fairly complicated constructor, as it has to make two important decisions: + * 1) Does it need to take ThreadCritical lock to write tracking record + * 2) Does it need to pre-reserve a sequence number for the tracking record + * + * The rules to determine if ThreadCritical is needed: + * 1. When nmt is in single-threaded bootstrapping mode, no lock is needed as VM + * still in single thread mode. + * 2. For all threads other than JavaThread, ThreadCritical is needed + * to write to recorders to global recorder. + * 3. For JavaThreads that are no longer visible by safepoint, also + * need to take ThreadCritical and records are written to global + * recorders, since these threads are NOT walked by Threads.do_thread(). + * 4. JavaThreads that are running in safepoint-safe states do not stop + * for safepoints, ThreadCritical lock should be taken to write + * memory records. + * 5. JavaThreads that are running in VM state do not need any lock and + * records are written to per-thread recorders. + * 6. For a thread has yet to attach VM 'Thread', they need to take + * ThreadCritical to write to global recorder. + * + * The memory operations that need pre-reserve sequence numbers: + * The memory operations that "release" memory blocks and the + * operations can fail, need to pre-reserve sequence number. They + * are realloc, uncommit and release. + * + * The reason for pre-reserve sequence number, is to prevent race condition: + * Thread 1 Thread 2 + * <release> + * <allocate> + * <write allocate record> + * <write release record> + * if Thread 2 happens to obtain the memory address Thread 1 just released, + * then NMT can mistakenly report the memory is free. + * + * Noticeably, free() does not need pre-reserve sequence number, because the call + * does not fail, so we can alway write "release" record before the memory is actaully + * freed. + * + * For realloc, uncommit and release, following coding pattern should be used: + * + * MemTracker::Tracker tkr = MemTracker::get_realloc_tracker(); + * ptr = ::realloc(...); + * if (ptr != NULL) { + * tkr.record(...) + * } else { + * tkr.discard(); + * } + * + * MemTracker::Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); + * if (uncommit(...)) { + * tkr.record(...); + * } else { + * tkr.discard(); + * } + * + * MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + * if (release(...)) { + * tkr.record(...); + * } else { + * tkr.discard(); + * } + * + * Since pre-reserved sequence number is only good for the generation that it is acquired, + * when there is pending Tracker that reserved sequence number, NMT sync-point has + * to be skipped to prevent from advancing generation. This is done by inc and dec + * MemTracker::_pending_op_count, when MemTracker::_pending_op_count > 0, NMT sync-point is skipped. + * Not all pre-reservation of sequence number will increment pending op count. For JavaThreads + * that honor safepoints, safepoint can not occur during the memory operations, so the + * pre-reserved sequence number won't cross the generation boundary. + */ +MemTracker::Tracker::Tracker(MemoryOperation op, Thread* thr) { + _op = NoOp; + _seq = 0; + if (MemTracker::is_on()) { + _java_thread = NULL; + _op = op; + + // figure out if ThreadCritical lock is needed to write this operation + // to MemTracker + if (MemTracker::is_single_threaded_bootstrap()) { + thr = NULL; + } else if (thr == NULL) { + // don't use Thread::current(), since it is possible that + // the calling thread has yet to attach to VM 'Thread', + // which will result assertion failure + thr = ThreadLocalStorage::thread(); + } + + if (thr != NULL) { + // Check NMT load + MemTracker::check_NMT_load(thr); + + if (thr->is_Java_thread() && ((JavaThread*)thr)->is_safepoint_visible()) { + _java_thread = (JavaThread*)thr; + JavaThreadState state = _java_thread->thread_state(); + // JavaThreads that are safepoint safe, can run through safepoint, + // so ThreadCritical is needed to ensure no threads at safepoint create + // new records while the records are being gathered and the sequence number is changing + _need_thread_critical_lock = + SafepointSynchronize::safepoint_safe(_java_thread, state); + } else { + _need_thread_critical_lock = true; + } + } else { + _need_thread_critical_lock + = !MemTracker::is_single_threaded_bootstrap(); + } + + // see if we need to pre-reserve sequence number for this operation + if (_op == Realloc || _op == Uncommit || _op == Release) { + if (_need_thread_critical_lock) { + ThreadCritical tc; + MemTracker::inc_pending_op_count(); + _seq = SequenceGenerator::next(); + } else { + // for the threads that honor safepoints, no safepoint can occur + // during the lifespan of tracker, so we don't need to increase + // pending op count. + _seq = SequenceGenerator::next(); + } + } + } +} + +void MemTracker::Tracker::discard() { + if (MemTracker::is_on() && _seq != 0) { + if (_need_thread_critical_lock) { + ThreadCritical tc; + MemTracker::dec_pending_op_count(); + } + _seq = 0; + } +} + + +void MemTracker::Tracker::record(address old_addr, address new_addr, size_t size, + MEMFLAGS flags, address pc) { + assert(old_addr != NULL && new_addr != NULL, "Sanity check"); + assert(_op == Realloc || _op == NoOp, "Wrong call"); + if (MemTracker::is_on() && NMT_CAN_TRACK(flags) && _op != NoOp) { + assert(_seq > 0, "Need pre-reserve sequence number"); + if (_need_thread_critical_lock) { + ThreadCritical tc; + // free old address, use pre-reserved sequence number + MemTracker::write_tracking_record(old_addr, MemPointerRecord::free_tag(), + 0, _seq, pc, _java_thread); + MemTracker::write_tracking_record(new_addr, flags | MemPointerRecord::malloc_tag(), + size, SequenceGenerator::next(), pc, _java_thread); + // decrement MemTracker pending_op_count + MemTracker::dec_pending_op_count(); + } else { + // free old address, use pre-reserved sequence number + MemTracker::write_tracking_record(old_addr, MemPointerRecord::free_tag(), + 0, _seq, pc, _java_thread); + MemTracker::write_tracking_record(new_addr, flags | MemPointerRecord::malloc_tag(), + size, SequenceGenerator::next(), pc, _java_thread); + } + _seq = 0; + } +} + +void MemTracker::Tracker::record(address addr, size_t size, MEMFLAGS flags, address pc) { + // OOM already? + if (addr == NULL) return; + + if (MemTracker::is_on() && NMT_CAN_TRACK(flags) && _op != NoOp) { + bool pre_reserved_seq = (_seq != 0); + address pc = CALLER_CALLER_PC; + MEMFLAGS orig_flags = flags; + + // or the tagging flags + switch(_op) { + case Malloc: + flags |= MemPointerRecord::malloc_tag(); + break; + case Free: + flags = MemPointerRecord::free_tag(); + break; + case Realloc: + fatal("Use the other Tracker::record()"); + break; + case Reserve: + case ReserveAndCommit: + flags |= MemPointerRecord::virtual_memory_reserve_tag(); + break; + case Commit: + flags = MemPointerRecord::virtual_memory_commit_tag(); + break; + case Type: + flags |= MemPointerRecord::virtual_memory_type_tag(); + break; + case Uncommit: + assert(pre_reserved_seq, "Need pre-reserve sequence number"); + flags = MemPointerRecord::virtual_memory_uncommit_tag(); + break; + case Release: + assert(pre_reserved_seq, "Need pre-reserve sequence number"); + flags = MemPointerRecord::virtual_memory_release_tag(); + break; + case ArenaSize: + // a bit of hack here, add a small postive offset to arena + // address for its size record, so the size record is sorted + // right after arena record. + flags = MemPointerRecord::arena_size_tag(); + addr += sizeof(void*); + break; + case StackRelease: + flags = MemPointerRecord::virtual_memory_release_tag(); + break; + default: + ShouldNotReachHere(); + } + + // write memory tracking record + if (_need_thread_critical_lock) { + ThreadCritical tc; + if (_seq == 0) _seq = SequenceGenerator::next(); + MemTracker::write_tracking_record(addr, flags, size, _seq, pc, _java_thread); + if (_op == ReserveAndCommit) { + MemTracker::write_tracking_record(addr, orig_flags | MemPointerRecord::virtual_memory_commit_tag(), + size, SequenceGenerator::next(), pc, _java_thread); + } + if (pre_reserved_seq) MemTracker::dec_pending_op_count(); + } else { + if (_seq == 0) _seq = SequenceGenerator::next(); + MemTracker::write_tracking_record(addr, flags, size, _seq, pc, _java_thread); + if (_op == ReserveAndCommit) { + MemTracker::write_tracking_record(addr, orig_flags | MemPointerRecord::virtual_memory_commit_tag(), + size, SequenceGenerator::next(), pc, _java_thread); + } + } + _seq = 0; + } +} +
--- a/src/share/vm/services/memTracker.hpp Wed Jun 12 19:58:20 2013 -0700 +++ b/src/share/vm/services/memTracker.hpp Thu Jun 13 10:26:22 2013 -0700 @@ -93,6 +93,45 @@ }; public: + class Tracker : public StackObj { + friend class MemTracker; + public: + enum MemoryOperation { + NoOp, // no op + Malloc, // malloc + Realloc, // realloc + Free, // free + Reserve, // virtual memory reserve + Commit, // virtual memory commit + ReserveAndCommit, // virtual memory reserve and commit + StackAlloc = ReserveAndCommit, // allocate thread stack + Type, // assign virtual memory type + Uncommit, // virtual memory uncommit + Release, // virtual memory release + ArenaSize, // set arena size + StackRelease // release thread stack + }; + + + protected: + Tracker(MemoryOperation op, Thread* thr = NULL); + + public: + void discard(); + + void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL); + void record(address old_addr, address new_addr, size_t size, + MEMFLAGS flags, address pc = NULL); + + private: + bool _need_thread_critical_lock; + JavaThread* _java_thread; + MemoryOperation _op; // memory operation + jint _seq; // reserved sequence number + }; + + + public: // native memory tracking level enum NMTLevel { NMT_off, // native memory tracking is off @@ -196,7 +235,10 @@ // the second phase of bootstrapping, VM is about or already in multi-threaded mode static void bootstrap_multi_thread(); + private: + static Tracker _tkr; + public: // start() has to be called when VM still in single thread mode, but after // command line option parsing is done. static void start(); @@ -204,67 +246,42 @@ // record a 'malloc' call static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { - if (is_on() && NMT_CAN_TRACK(flags)) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, (flags|MemPointerRecord::malloc_tag()), size, pc, thread); - } + Tracker tkr(Tracker::Malloc, thread); + tkr.record(addr, size, flags, pc); } // record a 'free' call static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { - if (is_on() && NMT_CAN_TRACK(flags)) { - create_memory_record(addr, MemPointerRecord::free_tag(), 0, 0, thread); - } - } - // record a 'realloc' call - static inline void record_realloc(address old_addr, address new_addr, size_t size, - MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { - if (is_on() && NMT_CAN_TRACK(flags)) { - assert(size > 0, "Sanity check"); - record_free(old_addr, flags, thread); - record_malloc(new_addr, size, flags, pc, thread); - } + Tracker tkr(Tracker::Free, thread); + tkr.record(addr, 0, flags, DEBUG_CALLER_PC); } - // record arena memory size static inline void record_arena_size(address addr, size_t size) { - // we add a positive offset to arena address, so we can have arena memory record - // sorted after arena record - if (is_on() && !UseMallocOnly) { - assert(addr != NULL, "Sanity check"); - create_memory_record((addr + sizeof(void*)), MemPointerRecord::arena_size_tag(), size, - DEBUG_CALLER_PC, NULL); - } + Tracker tkr(Tracker::ArenaSize); + tkr.record(addr, size); } // record a virtual memory 'reserve' call static inline void record_virtual_memory_reserve(address addr, size_t size, - address pc = 0, Thread* thread = NULL) { + MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { if (is_on()) { assert(size > 0, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag(), - size, pc, thread); + Tracker tkr(Tracker::Reserve, thread); + tkr.record(addr, size, flags, pc); } } static inline void record_thread_stack(address addr, size_t size, Thread* thr, address pc = 0) { if (is_on()) { - assert(size > 0 && thr != NULL, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag() | mtThreadStack, - size, pc, thr); - create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag() | mtThreadStack, - size, pc, thr); + Tracker tkr(Tracker::StackAlloc, thr); + tkr.record(addr, size, mtThreadStack, pc); } } static inline void release_thread_stack(address addr, size_t size, Thread* thr) { if (is_on()) { - assert(size > 0 && thr != NULL, "Sanity check"); - assert(!thr->is_Java_thread(), "too early"); - create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag() | mtThreadStack, - size, DEBUG_CALLER_PC, thr); - create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag() | mtThreadStack, - size, DEBUG_CALLER_PC, thr); + Tracker tkr(Tracker::StackRelease, thr); + tkr.record(addr, size, mtThreadStack, DEBUG_CALLER_PC); } } @@ -272,43 +289,45 @@ static inline void record_virtual_memory_commit(address addr, size_t size, address pc, Thread* thread = NULL) { if (is_on()) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag(), - size, pc, thread); + Tracker tkr(Tracker::Commit, thread); + tkr.record(addr, size, mtNone, pc); } } - // record a virtual memory 'uncommit' call - static inline void record_virtual_memory_uncommit(address addr, size_t size, - Thread* thread = NULL) { + static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size, + MEMFLAGS flags, address pc, Thread* thread = NULL) { if (is_on()) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag(), - size, DEBUG_CALLER_PC, thread); + Tracker tkr(Tracker::ReserveAndCommit, thread); + tkr.record(addr, size, flags, pc); } } - // record a virtual memory 'release' call - static inline void record_virtual_memory_release(address addr, size_t size, - Thread* thread = NULL) { - if (is_on()) { - assert(size > 0, "Sanity check"); - create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag(), - size, DEBUG_CALLER_PC, thread); - } - } // record memory type on virtual memory base address static inline void record_virtual_memory_type(address base, MEMFLAGS flags, Thread* thread = NULL) { if (is_on()) { - assert(base > 0, "wrong base address"); - assert((flags & (~mt_masks)) == 0, "memory type only"); - create_memory_record(base, (flags | MemPointerRecord::virtual_memory_type_tag()), - 0, DEBUG_CALLER_PC, thread); + Tracker tkr(Tracker::Type); + tkr.record(base, 0, flags); } } + // Get memory trackers for memory operations that can result race conditions. + // The memory tracker has to be obtained before realloc, virtual memory uncommit + // and virtual memory release, and call tracker.record() method if operation + // succeeded, or tracker.discard() to abort the tracking. + static inline Tracker get_realloc_tracker() { + return Tracker(Tracker::Realloc); + } + + static inline Tracker get_virtual_memory_uncommit_tracker() { + return Tracker(Tracker::Uncommit); + } + + static inline Tracker get_virtual_memory_release_tracker() { + return Tracker(Tracker::Release); + } + // create memory baseline of current memory snapshot static bool baseline(); @@ -372,6 +391,31 @@ static MemRecorder* get_pending_recorders(); static void delete_all_pending_recorders(); + // write a memory tracking record in recorder + static void write_tracking_record(address addr, MEMFLAGS type, + size_t size, jint seq, address pc, JavaThread* thread); + + static bool is_single_threaded_bootstrap() { + return _state == NMT_bootstrapping_single_thread; + } + + static void check_NMT_load(Thread* thr) { + assert(thr != NULL, "Sanity check"); + if (_slowdown_calling_thread && thr != _worker_thread) { + os::yield_all(); + } + } + + static void inc_pending_op_count() { + Atomic::inc(&_pending_op_count); + } + + static void dec_pending_op_count() { + Atomic::dec(&_pending_op_count); + assert(_pending_op_count >= 0, "Sanity check"); + } + + private: // retrieve a pooled memory record or create new one if there is not // one available @@ -450,6 +494,12 @@ // if NMT should slow down calling thread to allow // worker thread to catch up static volatile bool _slowdown_calling_thread; + + // pending memory op count. + // Certain memory ops need to pre-reserve sequence number + // before memory operation can happen to avoid race condition. + // See MemTracker::Tracker for detail + static volatile jint _pending_op_count; }; #endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/CompilerConfigFileWarning.java Thu Jun 13 10:26:22 2013 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7167142 + * @summary Warn if unused .hotspot_compiler file is present + * @library /testlibrary + */ + +import java.io.PrintWriter; +import com.oracle.java.testlibrary.*; + +public class CompilerConfigFileWarning { + public static void main(String[] args) throws Exception { + String vmVersion = System.getProperty("java.vm.version"); + if (vmVersion.toLowerCase().contains("debug") || vmVersion.toLowerCase().contains("jvmg")) { + System.out.println("Skip on debug builds since we'll always read the file there"); + return; + } + + PrintWriter pw = new PrintWriter(".hotspot_compiler"); + pw.println("aa"); + pw.close(); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: .hotspot_compiler file is present but has been ignored. Run with -XX:CompileCommandFile=.hotspot_compiler to load the file."); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CommandLine/ConfigFileWarning.java Thu Jun 13 10:26:22 2013 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7167142 + * @summary Warn if unused .hotspot_rc file is present + * @library /testlibrary + */ + +import java.io.PrintWriter; +import com.oracle.java.testlibrary.*; + +public class ConfigFileWarning { + public static void main(String[] args) throws Exception { + String vmVersion = System.getProperty("java.vm.version"); + if (vmVersion.toLowerCase().contains("debug") || vmVersion.toLowerCase().contains("jvmg")) { + System.out.println("Skip on debug builds since we'll always read the file there"); + return; + } + + PrintWriter pw = new PrintWriter(".hotspotrc"); + pw.println("aa"); + pw.close(); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("warning: .hotspotrc file is present but has been ignored. Run with -XX:Flags=.hotspotrc to load the file."); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/JcmdDiffCallsite.java Thu Jun 13 10:26:22 2013 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test detail memory comparison against early baseline + * @bug 8013917 + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build JcmdDiffCallsite + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail JcmdDiffCallsite + */ + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +public class JcmdDiffCallsite { + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + WhiteBox wb = WhiteBox.getWhiteBox(); + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + // Use WB API to alloc and free with the mtTest type + long memAlloc1 = wb.NMTMalloc(512 * 1024); + + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + + // Run 'jcmd <pid> VM.native_memory baseline' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "baseline"}); + pb.start(); + + wb.NMTFree(memAlloc1); + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + + // Run 'jcmd <pid> VM.native_memory detail.diff' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff"}); + output = new OutputAnalyzer(pb.start()); + + + // Use WB API to ensure that all data has been merged before we continue + if (!wb.NMTWaitForDataMerge()) { + throw new Exception("Call to WB API NMTWaitForDataMerge() failed"); + } + + // above malloc callsite should report 0 + output = new OutputAnalyzer(pb.start()); + output.shouldContain("(malloc=0"); + } +}