hotspot 默认 gc
在我以前的博客文章热点选项中的Java 8改进的文档 ,我写的误解围绕热点JVM非标准的默认设置选项 -XX:MaxDirectMemorySize
。 在本文中,我介绍了一种确定HotSpot JVM中“默认”最大直接内存大小的简单方法。
Java启动器的Java 8文档对-XX:MaxDirectMemorySize
声明了以下内容(我强调了 ):
设置新I / O(
java.nio
程序包)直接缓冲区分配的最大总大小(以字节为单位)。 字母k
或K
表示千字节,m
或M
表示兆字节,g
或G
表示千兆字节。 默认情况下,大小设置为0,这意味着JVM会自动为NIO直接缓冲区分配选择大小。
上面解释了,如果没有通过-XX:MaxDirectMemorySize
选项明确指定大小,则HotSpot中最大直接内存大小的默认值为0 。 在这种情况下,使用-XX:+ PrintFlagsInitial和-XX:+ PrintFlagsFinal之类的选项无济于事,因为当未明确指定时,这些值也将显示为零。 例如,运行java -XX:+PrintFlagsFinal -version
显示:
size_t MaxDirectMemorySize = 0
据我所知,没有“标准”方式来访问最大直接内存大小。 类java.lang.Runtime提供有关JVM中的近似可用内存,JVM中的总内存以及JVM将尝试使用的最大内存的信息 。 尽管java.lang.management.MemoryMXBean除了提供堆内存使用之外还提供了非 堆内存使用 ,但是这种非堆使用是指“方法区域”,也可能是实现的“内部处理或优化”,而不是直接用于内存。
有一些非标准的方法来确定一个人的HotSpot JVM默认的最大内存大小。 在StackOverflow线程中, 有没有一种方法可以测量Java中的直接内存使用情况? whiskeyspider撰写了有关sun.misc.SharedSecrets.getJavaNioAccess()。getDirectBufferPool()。getMemoryUsed()和sun.misc.VM.maxDirectMemory()的文章 。 这些特定于HotSpot的类分别指示正在使用的直接内存量和可以使用的最大直接内存量。
sun.misc.SharedSecrets类通过方法调用getJavaNioAccess().getDirectBufferPool()
来访问sun.misc.JavaNioAccess.BufferPool
的实例,提供有关直接内存使用的信息。 BufferPool
接口定义了三种提供直接内存相关详细信息的方法: getCount()
, getTotalCapacity()
和getMemoryUsed()
。 尽管这些方法提供了有关直接内存使用的有趣信息,但它们并没有告诉我们最大直接内存是多少。
HotSpot JVM中的sun.misc.VM.maxDirectMemory()方法为我们提供最大直接内存,无论它是使用-XX:MaxDirectMemorySize=
显式指定的,还是隐式设置为-XX:MaxDirectMemorySize=0
(默认值) VM选择直接内存的最大大小。
为了帮助演示使用这些方法确定最大直接内存和使用的直接内存,我首先介绍一个将在示例中使用的实用程序。 这个enum
被命名为MemoryUnit
,并且适用于ustin.utilities.memory.MemoryUnit.java中的这篇文章。 我本可以使用Apache Commons的FileUtils.byteCountToDisplaySize(long)或Brice McIver对其进行的更精细的修改 ,但决定使用这个简单的TimeUnit – 启发性的 enum
,如下所示。
MemoryUnit.java
package dustin.examples.maxdirectmemory;/*** Representation of basic memory units.*/
public enum MemoryUnit
{/** Smallest memory unit. */BYTES,/** "One thousand" (1024) bytes. */KILOBYTES,/** "One million" (1024x1024) bytes. */MEGABYTES,/** "One billion" (1024x1024x1024) bytes. */GIGABYTES;/** Number of bytes in a kilobyte. */private final double BYTES_PER_KILOBYTE = 1024.0;/** Number of kilobytes in a megabyte. */private final double KILOBYTES_PER_MEGABYTE = 1024.0;/** Number of megabytes per gigabyte. */private final double MEGABYTES_PER_GIGABYTE = 1024.0;/*** Returns the number of bytes corresponding to the* provided input for a particular unit of memory.** @param input Number of units of memory.* @return Number of bytes corresponding to the provided* number of particular memory units.*/public double toBytes(final long input){double bytes;switch (this){case BYTES:bytes = input;break;case KILOBYTES:bytes = input * BYTES_PER_KILOBYTE;break;case MEGABYTES:bytes = input * BYTES_PER_KILOBYTE * KILOBYTES_PER_MEGABYTE;break;case GIGABYTES:bytes = input * BYTES_PER_KILOBYTE * KILOBYTES_PER_MEGABYTE * MEGABYTES_PER_GIGABYTE;break;default :throw new RuntimeException("No value '" + this + "' recognized for enum MemoryUnit.");}return bytes;}/*** Returns the number of kilobytes corresponding to the* provided input for a particular unit of memory.** @param input Number of units of memory.* @return Number of kilobytes corresponding to the provided* number of particular memory units.*/public double toKiloBytes(final long input){double kilobytes;switch (this){case BYTES:kilobytes = input / BYTES_PER_KILOBYTE;break;case KILOBYTES:kilobytes = input;break;case MEGABYTES:kilobytes = input * KILOBYTES_PER_MEGABYTE;break;case GIGABYTES:kilobytes = input * KILOBYTES_PER_MEGABYTE * MEGABYTES_PER_GIGABYTE;break;default:throw new RuntimeException("No value '" + this + "' recognized for enum MemoryUnit.");}return kilobytes;}/*** Returns the number of megabytes corresponding to the* provided input for a particular unit of memory.** @param input Number of units of memory.* @return Number of megabytes corresponding to the provided* number of particular memory units.*/public double toMegaBytes(final long input){double megabytes;switch (this){case BYTES:megabytes = input / BYTES_PER_KILOBYTE / KILOBYTES_PER_MEGABYTE;break;case KILOBYTES:megabytes = input / KILOBYTES_PER_MEGABYTE;break;case MEGABYTES:megabytes = input;break;case GIGABYTES:megabytes = input * MEGABYTES_PER_GIGABYTE;break;default:throw new RuntimeException("No value '" + this + "' recognized for enum MemoryUnit.");}return megabytes;}/*** Returns the number of gigabytes corresponding to the* provided input for a particular unit of memory.** @param input Number of units of memory.* @return Number of gigabytes corresponding to the provided* number of particular memory units.*/public double toGigaBytes(final long input){double gigabytes;switch (this){case BYTES:gigabytes = input / BYTES_PER_KILOBYTE / KILOBYTES_PER_MEGABYTE / MEGABYTES_PER_GIGABYTE;break;case KILOBYTES:gigabytes = input / KILOBYTES_PER_MEGABYTE / MEGABYTES_PER_GIGABYTE;break;case MEGABYTES:gigabytes = input / MEGABYTES_PER_GIGABYTE;break;case GIGABYTES:gigabytes = input;break;default:throw new RuntimeException("No value '" + this + "' recognized for enum MemoryUnit.");}return gigabytes;}
}
使用MemoryUnit
作为帮助程序实用程序,下一个代码示例演示如何使用SharedSecrets提供的JavaNioAccess.BufferPool上的方法。 这些值不是最大可能的直接内存,而是对已经使用的直接内存的估计。
/*** Write amount of direct memory used to standard output* using SharedSecrets, JavaNetAccess, the direct Buffer Pool,* and methods getMemoryUsed() and getTotalCapacity().*/
public static void writeUsedDirectMemoryToStdOut()
{final double sharedSecretsMemoryUsed =MemoryUnit.BYTES.toMegaBytes(SharedSecrets.getJavaNioAccess().getDirectBufferPool().getMemoryUsed());out.println("sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPool().getMemoryUsed(): "+ sharedSecretsMemoryUsed + " MB");final double sharedSecretsTotalCapacity =MemoryUnit.BYTES.toMegaBytes(SharedSecrets.getJavaNioAccess().getDirectBufferPool().getTotalCapacity());out.println("sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPool().getTotalCapacity(): "+ sharedSecretsTotalCapacity + " MB");
}
将类似以下内容的行放入直接存储器后,即可执行以上代码:
final ByteBuffer bytes = ByteBuffer.allocateDirect(1_000_000);
如上所示使用直接内存并执行上面的代码时,输出如下所示:
sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPool().getMemoryUsed(): 0.95367431640625 MB
sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPool().getTotalCapacity(): 0.95367431640625 MB
刚刚演示的方法提供了使用的直接内存量的估计,但仍未显示最大可用直接内存。 可以使用VM.maxDirectMemory
确定,如下面的代码清单所示。
/*** Write maximum direct memory size set (explicitly or* implicitly) for this VM instance using VM's* method maxDirectMemory().*/
public static void writeMaximumDirectMemorySizeToStdOut()
{final double vmSize =MemoryUnit.BYTES.toMegaBytes(VM.maxDirectMemory());out.println("sun.misc.VM.maxDirectMemory(): " + vmSize + " MB");
}
当以上代码在我的笔记本电脑上使用JDK 8执行且未明确指定-XX:MaxDirectMemorySize
,结果如下所示:
sun.misc.VM.maxDirectMemory(): 1804.5 MB
由此可见,我的机器上运行的JVM的默认最大直接内存大小约为1.8 GB。 我知道这是默认值,因为我没有在命令行上显式指定-XX:MaxDirectMemorySize
,并且因为使用-XX:+ PrintFlagsFinal运行示例Java应用程序时显示为零(默认值)。
为了确保自己这种方法显示的是正确的最大直接内存,我可以在命令行上显式指定最大直接内存,并查看上面显示的代码写了什么。 在这种情况下,我在命令行上提供-XX:MaxDirectMemorySize=3G
。 这是我使用显式设置运行上述代码时的输出:
sun.misc.VM.maxDirectMemory(): 3072.0 MB
结论
当需要知道可在HotSpot JVM上运行的特定应用程序使用的最大直接内存时 ,如果未明确指定-XX:MaxDirectMemorySize
,则方法VM.maxDirectMemory()
可能是获取此信息的最简单方法。 当直接使用Java NIO时 ,甚至当使用Java NIO的产品(例如Terracotta和Hazelcast “ offheap”选项)间接使用Java NIO时,了解允许的最大直接内存将很有用。
翻译自: https://www.javacodegeeks.com/2016/02/default-hotspot-maximum-direct-memory-size.html
hotspot 默认 gc