一. 前言

今天看到一句话 , 有点懵, 所以验证一下.

使用sun.misc.Unsafe的allocateMemory方法分配堆外内存。不受-XX:MaxDirectMemorySize这个JVM参数的限制

二. 结论

上面的结论有点不完善:

  1. 如果通过反射的方式拿到Unsafe的实例,然后用Unsafe的allocateMemory方法分配堆外内存. 确实不受-XX:MaxDirectMemorySize这个JVM参数的限制 . 所以限制的内存大小为操作系统的内存.

  2. 如果使用Java自带的 ByteBuffer.allocateDirect(size) 或者直接 new DirectByteBuffer(capacity) , 这样受-XX:MaxDirectMemorySize 这个JVM参数的限制. 其实底层都是用的Unsafe#allocateMemory,区别是对大小做了限制. 如果超出限制直接OOM.

  3. 如果不设置-XX:MaxDirectMemorySize 默认的话,是跟堆内存大小保持一致. [堆内存大小如果不设置的话,默认为操作系统的 1/4, 所以 DirectMemory的大小限制JVM的Runtime.getRuntime().maxMemory()内存大小 . ], 代码入下:

sun.misc.VM

public static void saveAndRemoveProperties(Properties var0) {if (booted) {throw new IllegalStateException("System initialization has completed");} else {savedProps.putAll(var0);String var1 = (String)var0.remove("sun.nio.MaxDirectMemorySize");if (var1 != null) {if (var1.equals("-1")) {// 默认值 -1 , 代表是JVM的最大内存 (注意,不是操作系统内存!!!!!!!!!). directMemory = Runtime.getRuntime().maxMemory();} else {long var2 = Long.parseLong(var1);if (var2 > -1L) {directMemory = var2;}}}var1 = (String)var0.remove("sun.nio.PageAlignDirectMemory");if ("true".equals(var1)) {pageAlignDirectMemory = true;}var1 = var0.getProperty("sun.lang.ClassLoader.allowArraySyntax");allowArraySyntax = var1 == null ? defaultAllowArraySyntax : Boolean.parseBoolean(var1);var0.remove("java.lang.Integer.IntegerCache.high");var0.remove("sun.zip.disableMemoryMapping");var0.remove("sun.java.launcher.diag");var0.remove("sun.cds.enableSharedLookupCache");}}

三. 代码验证: 反射获取Unsafe的allocateMemory方法

3.1. 测试代码


import com.sun.management.OperatingSystemMXBean;
import sun.misc.Unsafe;import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;public class DirectMemoryOOM_01 {// 内存限制失效// -Xms10m -Xmx10m -XX:MaxDirectMemorySize=10mpublic static void main(String[] args) throws Exception {Runtime rt = Runtime.getRuntime();long vmFree = 0;long vmUse = 0;long vmTotal = 0;long vmMax = 0;int byteToMb = 1024 * 1024;long size = 1024 * 1024 * 1024;Field f = Unsafe.class.getDeclaredFields()[0];f.setAccessible(true);Unsafe us = (Unsafe) f.get(null);List<Long> list = new ArrayList<Long>();while (true) {System.out.println("************ start ***************************");System.out.println("JVM maxDirectMemory : " + sun.misc.VM.maxDirectMemory() / byteToMb);vmTotal = rt.totalMemory() / byteToMb;vmFree = rt.freeMemory() / byteToMb;vmMax = rt.maxMemory() / byteToMb;vmUse = vmTotal - vmFree;System.out.println("JVM内存已用的空间为:" + vmUse + " MB");System.out.println("JVM内存的空闲空间为:" + vmFree + " MB");System.out.println("JVM总内存空间为:" + vmTotal + " MB");System.out.println("JVM总内存空间为:" + vmMax + " MB");System.out.println("======================================");// 操作系统级内存情况查询OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();String os = System.getProperty("os.name");long physicalFree = osmxb.getFreePhysicalMemorySize() / byteToMb;long physicalTotal = osmxb.getTotalPhysicalMemorySize() / byteToMb;long physicalUse = physicalTotal - physicalFree;System.out.println("操作系统的版本:" + os);System.out.println("操作系统物理内存已用的空间为:" + physicalUse + " MB");System.out.println("操作系统物理内存的空闲空间为:" + physicalFree + " MB");System.out.println("操作系统总物理内存:" + physicalTotal + " MB");System.out.println("======================================");// 获得线程总数ThreadGroup parentThread;int totalThread = 0;for (parentThread = Thread.currentThread().getThreadGroup(); parentThread.getParent() != null; parentThread = parentThread.getParent()) {totalThread = parentThread.activeCount();}System.out.println("获得线程总数:" + totalThread);System.out.println("======================================");long p = us.allocateMemory(size);for (int i = 0; i < size; i++) {us.putByte(p + i, Byte.MAX_VALUE);}list.add(p);System.out.println("************ end ***************************");Thread.sleep(1000);}}
}

3.2.设置JVM参数

-Xms10m -Xmx10m -XX:MaxDirectMemorySize=10m

3.2.输出结果: 不报错,无法限制内存.


************ start ***************************
JVM maxDirectMemory : 10
JVM内存已用的空间为:2 MB
JVM内存的空闲空间为:7 MB
JVM总内存空间为:9 MB
JVM总内存空间为:9 MB
======================================
操作系统的版本:Mac OS X
操作系统物理内存已用的空间为:16368 MB
操作系统物理内存的空闲空间为:16 MB
操作系统总物理内存:16384 MB
======================================
获得线程总数:2
======================================无限死循环中.....................
无限死循环中.....................
无限死循环中.....................
无限死循环中.....................
无限死循环中.....................
无限死循环中.....................
无限死循环中.....................

四. 代码验证: ByteBuffer.allocateDirect方式获取内存

4.1. 测试代码

package com.unsafe;import sun.misc.Unsafe;import java.lang.management.ManagementFactory;
import com.sun.management.OperatingSystemMXBean;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;public class DirectMemoryOOM_02 {// 内存限制失效// -Xms10m -Xmx10m -XX:MaxDirectMemorySize=10mpublic static void main(String[] args) throws Exception {Runtime rt = Runtime.getRuntime();long vmFree = 0;long vmUse = 0;long vmTotal = 0;long vmMax = 0;int byteToMb = 1024 * 1024;int size = 1024 * 1024 * 1024;List<ByteBuffer> list = new ArrayList<ByteBuffer>();while (true) {System.out.println("************ start ***************************");System.out.println("JVM maxDirectMemory : " + sun.misc.VM.maxDirectMemory() / byteToMb);vmTotal = rt.totalMemory() / byteToMb;vmFree = rt.freeMemory() / byteToMb;vmMax = rt.maxMemory() / byteToMb;vmUse = vmTotal - vmFree;System.out.println("JVM内存已用的空间为:" + vmUse + " MB");System.out.println("JVM内存的空闲空间为:" + vmFree + " MB");System.out.println("JVM总内存空间为:" + vmTotal + " MB");System.out.println("JVM总内存空间为:" + vmMax + " MB");System.out.println("======================================");// 操作系统级内存情况查询OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();String os = System.getProperty("os.name");long physicalFree = osmxb.getFreePhysicalMemorySize() / byteToMb;long physicalTotal = osmxb.getTotalPhysicalMemorySize() / byteToMb;long physicalUse = physicalTotal - physicalFree;System.out.println("操作系统的版本:" + os);System.out.println("操作系统物理内存已用的空间为:" + physicalUse + " MB");System.out.println("操作系统物理内存的空闲空间为:" + physicalFree + " MB");System.out.println("操作系统总物理内存:" + physicalTotal + " MB");System.out.println("======================================");// 获得线程总数ThreadGroup parentThread;int totalThread = 0;for (parentThread = Thread.currentThread().getThreadGroup(); parentThread.getParent() != null; parentThread = parentThread.getParent()) {totalThread = parentThread.activeCount();}System.out.println("获得线程总数:" + totalThread);System.out.println("======================================");// 分配 Direct MemoryByteBuffer by =  ByteBuffer.allocateDirect(size);list.add(by);System.out.println("************ end ***************************");Thread.sleep(1000);}}
}

4.2. 设置JVM参数

-Xms10m -Xmx10m -XX:MaxDirectMemorySize=10m

4.3. 输出结果: OutOfMemoryError: Direct buffer memory

************ start ***************************
JVM maxDirectMemory : 10
JVM内存已用的空间为:2 MB
JVM内存的空闲空间为:7 MB
JVM总内存空间为:9 MB
JVM总内存空间为:9 MB
======================================
操作系统的版本:Mac OS X
操作系统物理内存已用的空间为:13986 MB
操作系统物理内存的空闲空间为:2398 MB
操作系统总物理内存:16384 MB
======================================
获得线程总数:1
======================================
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memoryat java.nio.Bits.reserveMemory(Bits.java:695)at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)at com.unsafe.DirectMemoryOOM_02.main(DirectMemoryOOM_02.java:68)
Disconnected from the target VM, address: '127.0.0.1:58987', transport: 'socket'

[JVM]了断局: 堆外内存无法 [ -XX:MaxDirectMemorySize ] 限制相关推荐

  1. JVM初探- 使用堆外内存减少Full GC

    JVM初探-使用堆外内存减少Full GC 标签 : JVM 问题: 大部分主流互联网企业线上Server JVM选用了CMS收集器(如Taobao.LinkedIn.Vdian), 虽然CMS可与用 ...

  2. JVM NativeMemoryTracking 分析堆外内存泄露

    为什么80%的码农都做不了架构师?>>>    Native Memory Tracking (NMT) 是Hotspot VM用来分析VM内部内存使用情况的一个功能.我们可以利用j ...

  3. JVM初探——使用堆外内存减少Full GC

    问题: 大部分主流互联网企业线上Server JVM选用了CMS收集器(如Taobao.LinkedIn.Vdian), 虽然CMS可与用户线程并发GC以降低STW时间, 但它也并非十分完美, 尤其是 ...

  4. 阿里三面必问JVM知识点- 使用堆外内存减少Full GC

    问题: 大部分主流互联网企业线上Server JVM选用了CMS收集器(如Taobao.LinkedIn.Vdian), 虽然CMS可与用户线程并发GC以降低STW时间, 但它也并非十分完美, 尤其是 ...

  5. [JVM]了断局: [ 目录 ]

    [JVM]了断局: 说什么也没用,背就完了[必背] [JVM]了断局: "运行时数据区"理论梳理 [JVM]了断局: 虚拟机字节码指令表速查 [JVM]了断局: 类文件结构梳理 [ ...

  6. java 堆外内存泄露排查

    参考:http://blog.itpub.net/70016482/viewspace-2908649/ 一.原理 JDK提供绕过JVM直接在操作系统申请内存的接口,例如通过Unsafe类的alloc ...

  7. 一次完整的JVM堆外内存泄漏故障排查记录

    前言 记录一次线上JVM堆外内存泄漏问题的排查过程与思路,其中夹带一些JVM内存分配机制以及常用的JVM问题排查指令和工具分享,希望对大家有所帮助. 在整个排查过程中,我也走了不少弯路,但是在文章中我 ...

  8. jvm 堆外内存_NIO效率高的原理之零拷贝与直接内存映射

    更多内容,欢迎关注微信公众号:全菜工程师小辉~ 前言 在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理. 这篇博客将针对第三个原因,进行更详细的讲 ...

  9. java nio 堆外内存_Java堆外内存之突破JVM枷锁

    对于有Java开发经验的朋友都知道,Java中不需要手动的申请和释放内存,JVM会自动进行垃圾回收:而使用的内存是由JVM控制的. 那么,什么时机会进行垃圾回收,如何避免过度频繁的垃圾回收?如果JVM ...

最新文章

  1. 爬虫python下载-如何用Python爬虫实现百度图片自动下载?
  2. python mssql github_GitHub上最热门的开源项目都在这里了
  3. 红河学院计算机科学与技术,2016年红河学院计算机科学与技术专业最低分是多少?...
  4. Java Process getOutputStream()方法与示例
  5. 惠普暗影精灵3清灰_如何评价惠普笔记本这几年的表现?尤其是暗影精灵系列。...
  6. QTWebkit中的webkit/qt/api文档
  7. ubuntu设置vim语法高亮显示和自动缩进
  8. Compile、Make和Build的区别(as make, build, clean, run)
  9. noi.ac #289. 电梯(单调队列)
  10. Cocos2d 利用继承Draw方法制作可显示三维数据(宠物三维等)的三角形显示面板...
  11. 拓端tecdat|R语言高维数据惩罚回归方法:主成分回归PCR、岭回归、lasso、弹性网络elastic net分析基因数据
  12. php+ci+db+debug,[PHP] Web Framework : CodeIgniter MySQL Database 使用教學
  13. STM32选型与命名规则
  14. 华为手机计算机怎么用根号,根号下怎么打_根号怎么打出来华为_根号怎么打出来手机-Guide信息网...
  15. Windows系统文件浏览标签窗口工具
  16. [收藏] 今天的存储解决方案:直连式存储(DAS)、存储区域网络(SAN)、网络接入存储(NAS)
  17. inSSIDer使用方法
  18. 如何用计算机函数来求加权总分,Excel小技巧-使用函数「SUMPRODUCT」计算加权后的总和及平均值...
  19. web微信授权登陆-配置篇
  20. 智能家居系列之智能家居平台设计

热门文章

  1. 自己搭建php主机绑定域名,只需5步,教你用虚拟主机搭建出属于自己的网站
  2. Ai-Bot RPA自动化框架
  3. 医疗知识图谱问答系统(python neo4j)
  4. 计算机网络学习通习题
  5. Eth-Trunk捆绑技术
  6. Python中IO概述
  7. Selenium.Chrome相关配置及用法
  8. 团队软件开发第一次冲刺(七)
  9. 这个项目获2022世界物联网博览会三新成果奖!
  10. 局域网计算机修改网络用户,windows10怎么修改局域网网络名称