Path: blob/master/runtime/gc_base/GCExtensions.cpp
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "GCExtensions.hpp"2324#include "hookable_api.h"25#include "j9cfg.h"26#include "j2sever.h"27#include "j9memcategories.h"28#include "j9nongenerated.h"29#include "j9port.h"30#include "util_api.h"3132#include "EnvironmentBase.hpp"33#include "Forge.hpp"34#if defined(OMR_GC_IDLE_HEAP_MANAGER)35#include "IdleGCManager.hpp"36#endif /* defined(OMR_GC_IDLE_HEAP_MANAGER) */37#include "MemorySpace.hpp"38#include "MemorySubSpace.hpp"39#include "ObjectModel.hpp"40#include "ReferenceChainWalkerMarkMap.hpp"41#include "SublistPool.hpp"42#include "Wildcard.hpp"4344MM_GCExtensions *45MM_GCExtensions::newInstance(MM_EnvironmentBase *env)46{47PORT_ACCESS_FROM_ENVIRONMENT(env);48MM_GCExtensions *extensions;4950/* Avoid using MM_Forge to allocate memory for the extension, since MM_Forge itself has not been created! */51extensions = static_cast<MM_GCExtensions*>(j9mem_allocate_memory(sizeof(MM_GCExtensions), OMRMEM_CATEGORY_MM));52if (extensions) {53/* Initialize all the fields to zero */54memset((void *)extensions, 0, sizeof(*extensions));5556new(extensions) MM_GCExtensions();57if (!extensions->initialize(env)) {58extensions->kill(env);59return NULL;60}61}62return extensions;63}6465void66MM_GCExtensions::kill(MM_EnvironmentBase *env)67{68/* Avoid using MM_Forge to free memory for the extension, since MM_Forge was not used to allocate the memory */69PORT_ACCESS_FROM_ENVIRONMENT(env);70tearDown(env);71j9mem_free_memory(this);72}7374/**75* Initialize the global GC extensions structure.76* Clear all values within the extensions structure and call the appropriate initialization routines77* on all substructures. Upon completion of this call, the extensions structure is ready for use.78*79* @return true if the initialization was successful, false otherwise.80*/81bool82MM_GCExtensions::initialize(MM_EnvironmentBase *env)83{84PORT_ACCESS_FROM_ENVIRONMENT(env);8586if (!MM_GCExtensionsBase::initialize(env)) {87goto failed;88}8990#if defined(J9VM_GC_REALTIME)91/* only ref slots, size in bytes: 2 * minObjectSize - header size */92minArraySizeToSetAsScanned = 2 * (1 << J9VMGC_SIZECLASSES_LOG_SMALLEST) - J9JAVAVM_CONTIGUOUS_HEADER_SIZE(getJavaVM());93#endif /* J9VM_GC_REALTIME */9495#if defined(J9VM_GC_JNI_ARRAY_CACHE)96getJavaVM()->jniArrayCacheMaxSize = J9_GC_JNI_ARRAY_CACHE_SIZE;97#endif /* J9VM_GC_JNI_ARRAY_CACHE */9899#if defined(J9VM_GC_THREAD_LOCAL_HEAP)100getJavaVM()->gcInfo.tlhThreshold = J9_GC_TLH_THRESHOLD;101getJavaVM()->gcInfo.tlhSize = J9_GC_TLH_SIZE;102#endif /* J9VM_GC_THREAD_LOCAL_HEAP */103104/* if tuned for virtualized environment, we compromise a bit of performance for lower footprint */105if (getJavaVM()->runtimeFlags & J9_RUNTIME_TUNE_VIRTUALIZED) {106heapFreeMinimumRatioMultiplier = 20;107}108109padToPageSize = J9_ARE_ALL_BITS_SET(getJavaVM()->runtimeFlags, J9_RUNTIME_AGGRESSIVE);110111if (J9HookInitializeInterface(getHookInterface(), OMRPORT_FROM_J9PORT(PORTLIB), sizeof(hookInterface))) {112goto failed;113}114115initializeReferenceArrayCopyTable(&referenceArrayCopyTable);116117{118J9InternalVMFunctions const * const vmFuncs = getJavaVM()->internalVMFunctions;119_asyncCallbackKey = vmFuncs->J9RegisterAsyncEvent(getJavaVM(), memoryManagerAsyncCallbackHandler, getJavaVM());120_TLHAsyncCallbackKey = vmFuncs->J9RegisterAsyncEvent(getJavaVM(), memoryManagerTLHAsyncCallbackHandler, getJavaVM());121if ((_asyncCallbackKey < 0) || (_TLHAsyncCallbackKey < 0)) {122goto failed;123}124}125126#if defined(OMR_GC_IDLE_HEAP_MANAGER)127/* absorbs GC specific idle tuning flags */128if (J9_IDLE_TUNING_GC_ON_IDLE == (getJavaVM()->vmRuntimeStateListener.idleTuningFlags & J9_IDLE_TUNING_GC_ON_IDLE)) {129gcOnIdle = true;130}131if (J9_IDLE_TUNING_COMPACT_ON_IDLE == (getJavaVM()->vmRuntimeStateListener.idleTuningFlags & J9_IDLE_TUNING_COMPACT_ON_IDLE)) {132compactOnIdle = true;133}134idleMinimumFree = getJavaVM()->vmRuntimeStateListener.idleMinFreeHeap;135#endif /* if defined(OMR_GC_IDLE_HEAP_MANAGER) */136137return true;138139failed:140tearDown(env);141return false;142}143144/**145* Tear down the global GC extensions structure and all sub structures.146*/147void148MM_GCExtensions::tearDown(MM_EnvironmentBase *env)149{150J9InternalVMFunctions const * const vmFuncs = getJavaVM()->internalVMFunctions;151vmFuncs->J9UnregisterAsyncEvent(getJavaVM(), _TLHAsyncCallbackKey);152_TLHAsyncCallbackKey = -1;153vmFuncs->J9UnregisterAsyncEvent(getJavaVM(), _asyncCallbackKey);154_asyncCallbackKey = -1;155156#if defined(J9VM_GC_MODRON_TRACE) && !defined(J9VM_GC_REALTIME)157tgcTearDownExtensions(getJavaVM());158#endif /* J9VM_GC_MODRON_TRACE && !defined(J9VM_GC_REALTIME) */159160MM_Wildcard *wildcard = numaCommonThreadClassNamePatterns;161while (NULL != wildcard) {162MM_Wildcard *nextWildcard = wildcard->_next;163wildcard->kill(this);164wildcard = nextWildcard;165}166numaCommonThreadClassNamePatterns = NULL;167168J9HookInterface** tmpHookInterface = getHookInterface();169if((NULL != tmpHookInterface) && (NULL != *tmpHookInterface)){170(*tmpHookInterface)->J9HookShutdownInterface(tmpHookInterface);171*tmpHookInterface = NULL; /* avoid issues with double teardowns */172}173174#if defined(OMR_GC_IDLE_HEAP_MANAGER)175if (NULL != idleGCManager) {176idleGCManager->kill(env);177idleGCManager = NULL;178}179#endif /* defined(OMR_GC_IDLE_HEAP_MANAGER) */180181MM_GCExtensionsBase::tearDown(env);182}183184void185MM_GCExtensions::identityHashDataAddRange(MM_EnvironmentBase *env, MM_MemorySubSpace* subspace, UDATA size, void* lowAddress, void* highAddress)186{187J9IdentityHashData* hashData = getJavaVM()->identityHashData;188if (J9_IDENTITY_HASH_SALT_POLICY_STANDARD == hashData->hashSaltPolicy) {189if (MEMORY_TYPE_NEW == (subspace->getTypeFlags() & MEMORY_TYPE_NEW)) {190if (hashData->hashData1 == (UDATA)highAddress) {191/* Expanding low bound */192hashData->hashData1 = (UDATA)lowAddress;193} else if (hashData->hashData2 == (UDATA)lowAddress) {194/* Expanding high bound */195hashData->hashData2 = (UDATA)highAddress;196} else {197/* First expand */198Assert_MM_true(UDATA_MAX == hashData->hashData1);199Assert_MM_true(0 == hashData->hashData2);200hashData->hashData1 = (UDATA)lowAddress;201hashData->hashData2 = (UDATA)highAddress;202}203}204}205}206207void208MM_GCExtensions::identityHashDataRemoveRange(MM_EnvironmentBase *env, MM_MemorySubSpace* subspace, UDATA size, void* lowAddress, void* highAddress)209{210J9IdentityHashData* hashData = getJavaVM()->identityHashData;211if (J9_IDENTITY_HASH_SALT_POLICY_STANDARD == hashData->hashSaltPolicy) {212if (MEMORY_TYPE_NEW == (subspace->getTypeFlags() & MEMORY_TYPE_NEW)) {213if (hashData->hashData1 == (UDATA)lowAddress) {214/* Contracting low bound */215Assert_MM_true(hashData->hashData1 <= (UDATA)highAddress);216Assert_MM_true((UDATA)highAddress <= hashData->hashData2);217hashData->hashData1 = (UDATA)highAddress;218} else if (hashData->hashData2 == (UDATA)highAddress) {219/* Contracting high bound */220Assert_MM_true(hashData->hashData1 <= (UDATA)lowAddress);221Assert_MM_true((UDATA)lowAddress <= hashData->hashData2);222hashData->hashData2 = (UDATA)lowAddress;223} else {224Assert_MM_unreachable();225}226}227}228}229230void231MM_GCExtensions::updateIdentityHashDataForSaltIndex(UDATA index)232{233getJavaVM()->identityHashData->hashSaltTable[index] = (U_32)convertValueToHash(getJavaVM(), getJavaVM()->identityHashData->hashSaltTable[index]);234}235236/*237* computeDefaultMaxHeapForJava is for Java only, it will be called during gcParseCommandLineAndInitializeWithValues(),238* computeDefaultMaxHeap() will still be called during MM_GCExtensionsBase::initialize(), computeDefaultMaxHeapForJava() can overwrite value of memoryMax.239*/240void241MM_GCExtensions::computeDefaultMaxHeapForJava(bool enableOriginalJDK8HeapSizeCompatibilityOption)242{243OMRPORT_ACCESS_FROM_OMRVM(_omrVM);244245if (OMR_CGROUP_SUBSYSTEM_MEMORY == omrsysinfo_cgroup_are_subsystems_enabled(OMR_CGROUP_SUBSYSTEM_MEMORY)) {246if (omrsysinfo_cgroup_is_memlimit_set()) {247/* If running in a cgroup with memory limit > 1G, reserve at-least 512M for JVM's internal requirements248* like JIT compilation etc, and extend default max heap memory to at-most 75% of cgroup limit.249* The value reserved for JVM's internal requirements excludes heap. This value is a conservative250* estimate of the JVM's internal requirements, given that one compilation thread can use up to 256M.251*/252#define OPENJ9_IN_CGROUP_NATIVE_FOOTPRINT_EXCLUDING_HEAP ((U_64)512 * 1024 * 1024)253memoryMax = (uintptr_t)OMR_MAX((int64_t)(usablePhysicalMemory / 2), (int64_t)(usablePhysicalMemory - OPENJ9_IN_CGROUP_NATIVE_FOOTPRINT_EXCLUDING_HEAP));254memoryMax = (uintptr_t)OMR_MIN(memoryMax, (usablePhysicalMemory / 4) * 3);255#undef OPENJ9_IN_CGROUP_NATIVE_FOOTPRINT_EXCLUDING_HEAP256}257}258259#if defined(OMR_ENV_DATA64)260if (!enableOriginalJDK8HeapSizeCompatibilityOption) {261/* extend java default max memory to 25% of usable RAM */262memoryMax = OMR_MAX(memoryMax, usablePhysicalMemory / 4);263}264265/* limit maxheapsize up to MAXIMUM_HEAP_SIZE_RECOMMENDED_FOR_3BIT_SHIFT_COMPRESSEDREFS, then can set 3bit compressedrefs as the default */266memoryMax = OMR_MIN(memoryMax, MAXIMUM_HEAP_SIZE_RECOMMENDED_FOR_3BIT_SHIFT_COMPRESSEDREFS);267#endif /* OMR_ENV_DATA64 */268269memoryMax = MM_Math::roundToFloor(heapAlignment, memoryMax);270maxSizeDefaultMemorySpace = memoryMax;271}272273MM_OwnableSynchronizerObjectList *274MM_GCExtensions::getOwnableSynchronizerObjectListsExternal(J9VMThread *vmThread)275{276Assert_MM_true(!isConcurrentScavengerInProgress());277278return ownableSynchronizerObjectLists;279}280281282