本文主要研究一下jvm的-XX:MaxDirectMemorySize

-XX:MaxDirectMemorySize

-XX:MaxDirectMemorySize=size用于设置New I/O(java.nio) direct-buffer allocations的最大大小,size的单位可以使用k/K、m/M、g/G;如果没有设置该参数则默认值为0,意味着JVM自己自动给NIO direct-buffer allocations选择最大大小

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<String, String> 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 valueslineSeparator = 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 secretssetJavaLangAccess();// 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);}//......
}
复制代码

System的initPhase1方法会调用VM.saveProperties(tempProps)方法来保存一份系统配置供内部实现使用;其中tempProps为SystemProps.initProperties()

jvm.cpp

hotspot/share/prims/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 suppliedif (!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命令参数转换为key为sun.nio.MaxDirectMemorySize的属性

VM.saveProperties

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

public class VM {// the init level when the VM is fully initializedprivate 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=<size>".//// 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<String, String> 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 laterif (savedProps == null) {savedProps = props;}// Set the maximum amount of direct memory.  This value is controlled// by the vm option -XX:MaxDirectMemorySize=<size>.// 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 defaultdirectMemory = Runtime.getRuntime().maxMemory();} else {long l = Long.parseLong(s);if (l > -1)directMemory = l;}// Check if direct buffers should be page aligneds = props.get("sun.nio.PageAlignDirectMemory");if ("true".equals(s))pageAlignDirectMemory = true;}//......
}
复制代码

VM的saveProperties方法读取sun.nio.MaxDirectMemorySize属性,如果为null或者是空或者是-1,那么则设置为Runtime.getRuntime().maxMemory();如果有设置MaxDirectMemorySize且值大于-1,那么使用该值作为directMemory的值;而VM的maxDirectMemory方法则返回的是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*/@Testpublic 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 module,要使用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大小,而非max值

使用API查看directBuffer使用情况

实例

    /*** -XX:MaxDirectMemorySize=60M*/@Testpublic 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大小

OOM

java.lang.OutOfMemoryError: Direct buffer memoryat java.base/java.nio.Bits.reserveMemory(Bits.java:175)at java.base/java.nio.DirectByteBuffer.<init>(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)
复制代码

从Other部分可以看到其值跟ByteBuffer.allocateDirect使用的值一致,改变ByteBuffer.allocateDirect的值再重新查看,可以发现Other部分跟着改变;因而初步断定Other部分应该是可以反映direct memory的使用大小

小结

  • -XX:MaxDirectMemorySize=size用于设置New I/O(java.nio) direct-buffer allocations的最大大小,size的单位可以使用k/K、m/M、g/G;如果没有设置该参数则默认值为0,意味着JVM自己自动给NIO direct-buffer allocations选择最大大小;从代码java.base/jdk/internal/misc/VM.java中可以看到默认是取的Runtime.getRuntime().maxMemory()
  • 使用jdk.internal.misc.VM.maxDirectMemory()可以获取maxDirectMemory的值;由于java9模块化之后,VM从原来的sun.misc.VM变更到java.base模块下的jdk.internal.misc.VM;上面代码默认是unamed module,要使用jdk.internal.misc.VM就需要使用--add-exports java.base/jdk.internal.misc=ALL-UNNAMED将其导出到UNNAMED,这样才可以运行
  • BufferPoolMXBean及JavaNioAccess.BufferPool(通过SharedSecrets获取)的getMemoryUsed可以获取direct memory的大小;其中java9模块化之后,SharedSecrets从原来的sun.misc.SharedSecrets变更到java.base模块下的jdk.internal.access.SharedSecrets;要使用--add-exports java.base/jdk.internal.access=ALL-UNNAMED将其导出到UNNAMED,这样才可以运行

另外使用NMT也可以查看direct memory的使用情况,其包含在了Other部分

doc

  • Default HotSpot Maximum Direct Memory Size
  • JVM源码分析之堆外内存完全解读
  • Java堆外内存增长问题排查Case
  • DirectByteBuffer堆外内存溢出问题排查
  • Default for XX:MaxDirectMemorySize
  • java.lang.OutOfMemoryError: Direct buffer memory (with tcnative) #6813
  • VM.java MaxDirectMemorySize
  • Summary of understanding "-XX:MaxDirectMemorySize" setting.
  • native-mem-tracking.md
  • Java Platform, Standard Edition Tools Reference

转载于:https://juejin.im/post/5c9ced366fb9a070e344c614

聊聊jvm的-XX:MaxDirectMemorySize相关推荐

  1. JVM -XX:MaxDirectMemorySize

    -XX:MaxDirectMemorySize 该参数指定了DirectByteBuffer能分配的空间的限额,如果没有显示指定这个参数启动jvm,默认值是xmx对应的值. DirectByteBuf ...

  2. [JVM]了断局: 堆外内存无法 [ -XX:MaxDirectMemorySize ] 限制

    一. 前言 今天看到一句话 , 有点懵, 所以验证一下. 使用sun.misc.Unsafe的allocateMemory方法分配堆外内存.不受-XX:MaxDirectMemorySize这个JVM ...

  3. 聊聊JVM(九)理解进入safepoint时如何让Java线程全部阻塞

    在这篇聊聊JVM(六)理解JVM的safepoint 中说了safepoint的基本概念,VM thread在进行GC前,必须要让所有的Java线程阻塞,从而stop the world,开始标记.J ...

  4. 聊聊JVM(六)理解JVM的safepoint

    safepoint是JVM里面很重要的一个概念,在很多场景下都会看到它,尤其是在GC的时候.这篇讲讲safepoint.本人不是做JVM实现研究的,很多地方只能点到为止,希望能够讲清楚这个概念,具体的 ...

  5. 聊聊JVM(三)两种计算Java对象大小的方法

    普通对象的结构如下,按64位机器的长度计算 1. 对象头(_mark), 8个字节 2. Oop指针,如果是32G内存以下的,默认开启对象指针压缩,4个字节 3. 数据区 4.Padding(内存对齐 ...

  6. -XX:MaxDirectMemorySize直接内存无效问题

    直接内存 直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现. 在JDK 1.4中 ...

  7. JVM参数-XX:+HeapDumpOnOutOfMemoryError使用方法

    1.配置方法 在JAVA_OPTIONS变量中增加 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${目录}. 例如:export JAVA_OPT ...

  8. 聊聊jvm的CompressedClassSpace

    序 本文主要研究一下jvm的CompressedClassSpace CompressedClassSpace java8移除了permanent generation,然后class metadat ...

  9. -XX:MaxDirectMemorySize

    -XX:MaxDirectMemorySize 最大堆外内存大小,此参数的含义是当Direct ByteBuffer分配的堆外内存到达指定大小后就触发Full GC. 首先可以在jdk文档中找到:关于 ...

最新文章

  1. 中学校园网建设实践与思考
  2. 【插件开发】—— 13 GEF双击模型事件
  3. 浮点数转换为整数四舍五入_定义宏以将浮点值四舍五入为C中最接近的整数
  4. rank,dense_rank,row_number使用和区别
  5. 微信封杀lol手游活动小程序?《英雄联盟手游》回应了
  6. wordpress 调用css,WordPress调用CSS最常用的方法有哪些?
  7. echarts鼠标放上去不显示值
  8. Map 3D中通过程序删除图层及数据源
  9. leetcode python3 简单题125. Valid Palindrome
  10. Python基础——mysql数据库、SQLAlchemy
  11. .NetCore源码阅读笔记系列之Security (四) Authentication AddJwtBearer
  12. mac使用bootcamp安装win7遇到的一些坑
  13. 如何查找并修改CAD图纸中的标注文字?
  14. Python中的timezone
  15. Android使用Volley框架显示“Cleartext HTTP traffic to XXX not permitted”的解决方法
  16. 混合策略与混合策略纳什均衡
  17. 新手怎么把java源码做成app_怎么样将1个编写好的程序源代码做成1个软件!
  18. SCI、EI论文框架
  19. 我们应当怎样做需求分析:非功能需求
  20. static_cast,dynamic_cast,const_cast详解

热门文章

  1. 【+】Linux Socket编程
  2. DLL劫持的发展历程
  3. 关于JDBC的一些笔记
  4. TabLayout和ViewPager
  5. 机房收费系统之处理流程图与DFD图
  6. FastDFS问题汇总
  7. 动态加入JS及加入CSS
  8. 如何手动更新Kafka中某个Topic的偏移量
  9. gh-ost 原理剖析
  10. 动态规划 53:Maximum Subarray,152:Maximum Subarray,266. Palindrome Permutation 回文全排列...