[JVM]了断局: 堆外内存无法 [ -XX:MaxDirectMemorySize ] 限制
一. 前言
今天看到一句话 , 有点懵, 所以验证一下.
使用sun.misc.Unsafe的allocateMemory方法分配堆外内存。不受
-XX:MaxDirectMemorySize
这个JVM参数的限制
二. 结论
上面的结论有点不完善:
如果通过反射的方式拿到Unsafe的实例,然后用Unsafe的allocateMemory方法分配堆外内存. 确实不受
-XX:MaxDirectMemorySize
这个JVM参数的限制 . 所以限制的内存大小为操作系统的内存.如果使用Java自带的
ByteBuffer.allocateDirect(size)
或者直接new DirectByteBuffer(capacity)
, 这样受-XX:MaxDirectMemorySize
这个JVM参数的限制. 其实底层都是用的Unsafe#allocateMemory
,区别是对大小做了限制. 如果超出限制直接OOM.如果不设置
-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 ] 限制相关推荐
- JVM初探- 使用堆外内存减少Full GC
JVM初探-使用堆外内存减少Full GC 标签 : JVM 问题: 大部分主流互联网企业线上Server JVM选用了CMS收集器(如Taobao.LinkedIn.Vdian), 虽然CMS可与用 ...
- JVM NativeMemoryTracking 分析堆外内存泄露
为什么80%的码农都做不了架构师?>>> Native Memory Tracking (NMT) 是Hotspot VM用来分析VM内部内存使用情况的一个功能.我们可以利用j ...
- JVM初探——使用堆外内存减少Full GC
问题: 大部分主流互联网企业线上Server JVM选用了CMS收集器(如Taobao.LinkedIn.Vdian), 虽然CMS可与用户线程并发GC以降低STW时间, 但它也并非十分完美, 尤其是 ...
- 阿里三面必问JVM知识点- 使用堆外内存减少Full GC
问题: 大部分主流互联网企业线上Server JVM选用了CMS收集器(如Taobao.LinkedIn.Vdian), 虽然CMS可与用户线程并发GC以降低STW时间, 但它也并非十分完美, 尤其是 ...
- [JVM]了断局: [ 目录 ]
[JVM]了断局: 说什么也没用,背就完了[必背] [JVM]了断局: "运行时数据区"理论梳理 [JVM]了断局: 虚拟机字节码指令表速查 [JVM]了断局: 类文件结构梳理 [ ...
- java 堆外内存泄露排查
参考:http://blog.itpub.net/70016482/viewspace-2908649/ 一.原理 JDK提供绕过JVM直接在操作系统申请内存的接口,例如通过Unsafe类的alloc ...
- 一次完整的JVM堆外内存泄漏故障排查记录
前言 记录一次线上JVM堆外内存泄漏问题的排查过程与思路,其中夹带一些JVM内存分配机制以及常用的JVM问题排查指令和工具分享,希望对大家有所帮助. 在整个排查过程中,我也走了不少弯路,但是在文章中我 ...
- jvm 堆外内存_NIO效率高的原理之零拷贝与直接内存映射
更多内容,欢迎关注微信公众号:全菜工程师小辉~ 前言 在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理. 这篇博客将针对第三个原因,进行更详细的讲 ...
- java nio 堆外内存_Java堆外内存之突破JVM枷锁
对于有Java开发经验的朋友都知道,Java中不需要手动的申请和释放内存,JVM会自动进行垃圾回收:而使用的内存是由JVM控制的. 那么,什么时机会进行垃圾回收,如何避免过度频繁的垃圾回收?如果JVM ...
最新文章
- 爬虫python下载-如何用Python爬虫实现百度图片自动下载?
- python mssql github_GitHub上最热门的开源项目都在这里了
- 红河学院计算机科学与技术,2016年红河学院计算机科学与技术专业最低分是多少?...
- Java Process getOutputStream()方法与示例
- 惠普暗影精灵3清灰_如何评价惠普笔记本这几年的表现?尤其是暗影精灵系列。...
- QTWebkit中的webkit/qt/api文档
- ubuntu设置vim语法高亮显示和自动缩进
- Compile、Make和Build的区别(as make, build, clean, run)
- noi.ac #289. 电梯(单调队列)
- Cocos2d 利用继承Draw方法制作可显示三维数据(宠物三维等)的三角形显示面板...
- 拓端tecdat|R语言高维数据惩罚回归方法:主成分回归PCR、岭回归、lasso、弹性网络elastic net分析基因数据
- php+ci+db+debug,[PHP] Web Framework : CodeIgniter MySQL Database 使用教學
- STM32选型与命名规则
- 华为手机计算机怎么用根号,根号下怎么打_根号怎么打出来华为_根号怎么打出来手机-Guide信息网...
- Windows系统文件浏览标签窗口工具
- [收藏] 今天的存储解决方案:直连式存储(DAS)、存储区域网络(SAN)、网络接入存储(NAS)
- inSSIDer使用方法
- 如何用计算机函数来求加权总分,Excel小技巧-使用函数「SUMPRODUCT」计算加权后的总和及平均值...
- web微信授权登陆-配置篇
- 智能家居系列之智能家居平台设计