jvmの-XX:MaxDirectMemorySizeについて話します



Talk About Jvms Xx Maxdirectmemorysize



シーケンス

この記事では、主にjvmの-XX:MaxDirectMemorySizeについて説明します。

-XX:MaxDirectMemorySize

-XX:MaxDirectMemorySize = sizeは、新しいI / Oを設定するために使用されます(java.nio直接バッファー割り当ての最大サイズ、ユニットのサイズは、このパラメーターの場合、k / K、m / M、g / Gを使用できますが設定されていない場合、デフォルト値は0です。これは、JVMがNIO直接バッファー割り当ての最大サイズを自動的に選択することを意味します。



System.initPhase1

java.base / java / lang / System.java

public final class System { /* Register the natives via the static initializer. * * VM will invoke the initializeSystemClass method to complete * the initialization for this class separated from clinit. * Note that to use properties set by the VM, see the constraints * described in the initializeSystemClass method. */ private static native void registerNatives() static { registerNatives() } /** Don't let anyone instantiate this class */ private System() { } /** * Initialize the system class. Called after thread initialization. */ private static void initPhase1() { // VM might invoke JNU_NewStringPlatform() to set those encoding // sensitive properties (user.home, user.name, boot.class.path, etc.) // during 'props' initialization. // The charset is initialized in System.c and does not depend on the Properties. Map tempProps = SystemProps.initProperties() VersionProps.init(tempProps) // There are certain system configurations that may be controlled by // VM options such as the maximum amount of direct memory and // Integer cache size used to support the object identity semantics // of autoboxing. Typically, the library will obtain these values // from the properties set by the VM. If the properties are for // internal implementation use only, these properties should be // masked from the system properties. // // Save a private copy of the system properties object that // can only be accessed by the internal implementation. VM.saveProperties(tempProps) props = createProperties(tempProps) StaticProperty.javaHome() // Load StaticProperty to cache the property values lineSeparator = props.getProperty('line.separator') FileInputStream fdIn = new FileInputStream(FileDescriptor.in) FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out) FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err) setIn0(new BufferedInputStream(fdIn)) setOut0(newPrintStream(fdOut, props.getProperty('sun.stdout.encoding'))) setErr0(newPrintStream(fdErr, props.getProperty('sun.stderr.encoding'))) // Setup Java signal handlers for HUP, TERM, and INT (where available). Terminator.setup() // Initialize any miscellaneous operating system settings that need to be // set for the class libraries. Currently this is no-op everywhere except // for Windows where the process-wide error mode is set before the java.io // classes are used. VM.initializeOSEnvironment() // The main thread is not added to its thread group in the same // way as other threads we must do it ourselves here. Thread current = Thread.currentThread() current.getThreadGroup().add(current) // register shared secrets setJavaLangAccess() // Subsystems that are invoked during initialization can invoke // VM.isBooted() in order to avoid doing things that should // wait until the VM is fully initialized. The initialization level // is incremented from 0 to 1 here to indicate the first phase of // initialization has completed. // IMPORTANT: Ensure that this remains the last initialization action! VM.initLevel(1) } //...... }

システムのinitPhase1メソッドはVM.saveProperties(tempProps)メソッドを呼び出して、tempPropsがSystemProps.initProperties()である内部実装用のシステム構成を保存します。



jvm.cpp

ホットスポット/共有/プリム/jvm.cpp

// Convert the -XX:MaxDirectMemorySize= command line flag // to the sun.nio.MaxDirectMemorySize property. // Do this after setting user properties to prevent people // from setting the value with a -D option, as requested. // Leave empty if not supplied if (!FLAG_IS_DEFAULT(MaxDirectMemorySize)) { char as_chars[256] jio_snprintf(as_chars, sizeof(as_chars), JULONG_FORMAT, MaxDirectMemorySize) Handle key_str = java_lang_String::create_from_platform_dependent_str('sun.nio.MaxDirectMemorySize', CHECK_NULL) Handle value_str = java_lang_String::create_from_platform_dependent_str(as_chars, CHECK_NULL) result_h->obj_at_put(ndx * 2, key_str()) result_h->obj_at_put(ndx * 2 + 1, value_str()) ndx++ }

jvm.cppには、-XX:MaxDirectMemorySizeコマンドパラメーターをキーsun.nio.MaxDirectMemorySizeを持つプロパティに変換するためのコードがあります。

VM.saveProperties

java.base / jdk / internal / misc / VM.java



public class VM { // the init level when the VM is fully initialized private static final int JAVA_LANG_SYSTEM_INITED = 1 private static final int MODULE_SYSTEM_INITED = 2 private static final int SYSTEM_LOADER_INITIALIZING = 3 private static final int SYSTEM_BOOTED = 4 private static final int SYSTEM_SHUTDOWN = 5 // 0, 1, 2, ... private static volatile int initLevel private static final Object lock = new Object() //...... // A user-settable upper limit on the maximum amount of allocatable direct // buffer memory. This value may be changed during VM initialization if // 'java' is launched with '-XX:MaxDirectMemorySize='. // // The initial value of this field is arbitrary during JRE initialization // it will be reset to the value specified on the command line, if any, // otherwise to Runtime.getRuntime().maxMemory(). // private static long directMemory = 64 * 1024 * 1024 // Returns the maximum amount of allocatable direct buffer memory. // The directMemory variable is initialized during system initialization // in the saveAndRemoveProperties method. // public static long maxDirectMemory() { return directMemory } //...... // Save a private copy of the system properties and remove // the system properties that are not intended for public access. // // This method can only be invoked during system initialization. public static void saveProperties(Map props) { if (initLevel() != 0) throw new IllegalStateException('Wrong init level') // only main thread is running at this time, so savedProps and // its content will be correctly published to threads started later if (savedProps == null) { savedProps = props } // Set the maximum amount of direct memory. This value is controlled // by the vm option -XX:MaxDirectMemorySize=. // The maximum amount of allocatable direct buffer memory (in bytes) // from the system property sun.nio.MaxDirectMemorySize set by the VM. // If not set or set to -1, the max memory will be used // The system property will be removed. String s = props.get('sun.nio.MaxDirectMemorySize') if (s == null || s.isEmpty() || s.equals('-1')) { // -XX:MaxDirectMemorySize not given, take default directMemory = Runtime.getRuntime().maxMemory() } else { long l = Long.parseLong(s) if (l > -1) directMemory = l } // Check if direct buffers should be page aligned s = props.get('sun.nio.PageAlignDirectMemory') if ('true'.equals(s)) pageAlignDirectMemory = true } //...... }

VMのsavePropertiesメソッドは、sun.nio.MaxDirectMemorySizeプロパティを読み取ります。 nullまたは空または-1の場合、Runtime.getRuntime()。maxMemory()に設定されます。MaxDirectMemorySizeが設定されていて、値が-1より大きい場合は、この値を使用します。この値は、directMemoryの値として使用されます。maxDirectMemoryメソッドVMのはdirectMemoryの値を返します。

maxDirectMemoryの値を取得します

インスタンス

public BufferPoolMXBean getDirectBufferPoolMBean(){ return ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class) .stream() .filter(e -> e.getName().equals('direct')) .findFirst() .orElseThrow() } public JavaNioAccess.BufferPool getNioBufferPool(){ return SharedSecrets.getJavaNioAccess().getDirectBufferPool() } /** * -XX:MaxDirectMemorySize=60M */ @Test public void testGetMaxDirectMemory(){ ByteBuffer.allocateDirect(25*1024*1024) System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024.0) System.out.println(VM.maxDirectMemory() / 1024.0 / 1024.0) System.out.println(getDirectBufferPoolMBean().getTotalCapacity() / 1024.0 / 1024.0) System.out.println(getNioBufferPool().getTotalCapacity() / 1024.0 / 1024.0) }

出力

出力は次のとおりです。

4096.0 60.0 25.0 25.0
  • java9はモジュール化されているため、VMは元のsun.misc.VMからjava.baseモジュールの下のjdk.internal.misc.VMに変更されます。上記のコードは、デフォルトでunamedモジュールになります。これは、jdk.internal.miscを使用するために必要です。 .VM --add-exports java.base / jdk.internal.misc = ALL-UNNAMED実行できるように、UNNAMEDにエクスポートします
  • java9のモジュール化後、SharedSecretsは元のsun.misc.SharedSecretsからjava.baseモジュールの下のjdk.internal.access.SharedSecretsに変更されました。使用--add-exports java.base / jdk.internal.access = ALL-UNNAMEDはそれをエクスポートします実行できるようにUNNAMEDに
  • 出力からわかるように、Runtime.getRuntime()。maxMemory()の値は正しく、BufferPoolMXBeanとJavaNioAccess.BufferPoolのgetTotalCapacityは、最大値ではなくdirectBufferサイズを返します。

APIを使用して、directBufferの使用を表示します

インスタンス

/** * -XX:MaxDirectMemorySize=60M */ @Test public void testGetDirectMemoryUsage(){ ByteBuffer.allocateDirect(30*1024*1024) System.out.println(getDirectBufferPoolMBean().getMemoryUsed() / 1024.0 / 1024.0) System.out.println(getNioBufferPool().getMemoryUsed() / 1024.0 / 1024.0) }

出力

出力は次のとおりです。

30.0 30.0

BufferPoolMXBeanとJavaNioAccess.BufferPoolのgetMemoryUsedがdirectBufferサイズを返すことができることがわかります。

おじさん

java.lang.OutOfMemoryError: Direct buffer memory at java.base/java.nio.Bits.reserveMemory(Bits.java:175) at java.base/java.nio.DirectByteBuffer.(DirectByteBuffer.java:118) at java.base/java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:317)

上記のByteBuffer.allocateDirectが60Mを超えて変更された場合、実行はOutOfMemoryErrorをスローします

NMTを使用してdirectBufferの使用状況を確認します

jcmd 3088 VM.native_memory scale=MB 3088: Native Memory Tracking: Total: reserved=5641MB, committed=399MB - Java Heap (reserved=4096MB, committed=258MB) (mmap: reserved=4096MB, committed=258MB) - Class (reserved=1032MB, committed=6MB) (classes #1609) ( instance classes #1460, array classes #149) (mmap: reserved=1032MB, committed=5MB) ( Metadata: ) ( reserved=8MB, committed=5MB) ( used=3MB) ( free=2MB) ( waste=0MB =0.00%) ( Class space:) ( reserved=1024MB, committed=1MB) ( used=0MB) ( free=0MB) ( waste=0MB =0.00%) - Thread (reserved=18MB, committed=18MB) (thread #18) (stack: reserved=18MB, committed=18MB) - Code (reserved=242MB, committed=7MB) (mmap: reserved=242MB, committed=7MB) - GC (reserved=203MB, committed=60MB) (malloc=18MB #2443) (mmap: reserved=185MB, committed=43MB) - Internal (reserved=1MB, committed=1MB) (malloc=1MB #1257) - Other (reserved=30MB, committed=30MB) (malloc=30MB #2) - Symbol (reserved=1MB, committed=1MB) (malloc=1MB #13745) - Shared class space (reserved=17MB, committed=17MB) (mmap: reserved=17MB, committed=17MB)

その他のセクションから、値がByteBuffer.allocateDirectで使用される値と同じであることがわかります。 ByteBuffer.allocateDirectの値を変更して、再表示します。その他の部分が変わっていることがわかります。したがって、その他の部分は直接メモリの使用を反映する必要があることが事前に決定されています。

概要

  • -XX:MaxDirectMemorySize = sizeは、新しいI / Oを設定するために使用されます(java.nio直接バッファー割り当ての最大サイズ、ユニットのサイズは、このパラメーターの場合、k / K、m / M、g / Gを使用できますが設定されていない場合、デフォルト値は0です。これは、JVMがコードjava.base / jdk / internal / misc / VM.javaから最大NIO直接バッファー割り当てサイズを自動的に選択することを意味します。デフォルトはランタイムであることがわかります。 getRuntime()。maxMemory()
  • maxDirectMemoryの値は、j​​ava9がモジュール化されているため、jdk.internal.misc.VM.maxDirectMemory()を使用して取得できます。VMは、java.baseの下で元のsun.misc.VMからjdk.internal.misc.VMに変更されます。 moduleコードのデフォルトは、名前のないモジュールです。 jdk.internal.misc.VMを使用するには、-add-exports java.base / jdk.internal.misc = ALL-UNNAMEDを使用してUNNAMEDにエクスポートし、実行できるようにする必要があります。
  • BufferPoolMXBeanおよびJavaNioAccess.BufferPool(Obtained through SharedSecrets getMemoryUsedは、java9がモジュール化された後、ダイレクトメモリのサイズを取得できます。SharedSecretsは元のsun.misc.SharedSecretsからjdk.internal.access.SharedSecretsに変更されます。 java.baseモジュールuse--add-exportsjava。Base/ jdk.internal.access = ALL-UNNAMEDは、実行できるようにUNNAMEDにエクスポートします。

さらに、「その他」セクションに含まれているNMTを使用して、直接メモリーの使用状況を表示することもできます。

doc