四、Direct buffer memory我们使用 NIO 的时候经常需要使用 ByteBuffer 来读取或写入数据,这是一种基于 Channel(通道) 和 Buffer(缓冲区)的 I/O 方式,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆里面的 DirectByteBuffer 对象作为这块内存的引用进行操作 。这样在一些场景就避免了 Java 堆和 Native 中来回复制数据,所以性能会有所提高 。
Java 允许应用程序通过 Direct ByteBuffer 直接访问堆外内存,许多高性能程序通过 Direct ByteBuffer 结合内存映射文件(Memory MApped File)实现高速 IO 。4.1 写个 bug
- ByteBuffer.allocate(capability) 是分配 JVM 堆内存,属于 GC 管辖范围,需要内存拷贝所以速度相对较慢;
- ByteBuffer.allocateDirect(capability) 是分配 OS 本地内存,不属于 GC 管辖范围,由于不需要内存拷贝所以速度相对较快;
/** * VM Options:-Xms10m,-Xmx10m,-XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m */public class DirectBufferMemoryDemo { public static void main(String[] args) { System.out.println("maxDirectMemory is:"+sun.misc.VM.maxDirectMemory() / 1024 / 1024 + "MB"); //ByteBuffer buffer = ByteBuffer.allocate(6*1024*1024); ByteBuffer buffer = ByteBuffer.allocateDirect(6*1024*1024); }}
最大直接内存,默认是电脑内存的 1/4,所以我们设小点,然后使用直接内存超过这个值,就会出现 OOM 。maxDirectMemory is:5MBException in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
4.2 解决方案- Java 只能通过 ByteBuffer.allocateDirect 方法使用 Direct ByteBuffer,因此,可以通过 Arthas 等在线诊断工具拦截该方法进行排查
- 检查是否直接或间接使用了 NIO,如 netty,jetty 等
- 通过启动参数 -XX:MaxDirectMemorySize 调整 Direct ByteBuffer 的上限值
- 检查 JVM 参数是否有 -XX:+DisableExplicitGC 选项,如果有就去掉,因为该参数会使 System.gc() 失效
- 检查堆外内存使用代码,确认是否存在内存泄漏;或者通过反射调用 sun.misc.Cleaner 的 clean() 方法来主动释放被 Direct ByteBuffer 持有的内存空间
- 内存容量确实不足,升级配置
5.1 写个 bug
public static void main(String[] args) { while(true){ new Thread(() -> { try { Thread.sleep(Integer.MAX_VALUE); } catch(InterruptedException e) { } }).start(); }}
Error occurred during initialization of VMjava.lang.OutOfMemoryError: unable to create new native thread
5.2 原因分析文章插图
JVM 向 OS 请求创建 native 线程失败,就会抛出 Unableto createnewnativethread,常见的原因包括以下几类:
- 线程数超过操作系统最大线程数限制(和平台有关)
- 线程数超过 kernel.pid_max(只能重启)
- native 内存不足;该问题发生的常见过程主要包括以下几步:
- JVM 内部的应用程序请求创建一个新的 Java 线程;
- JVM native 方法代理了该次请求,并向操作系统请求创建一个 native 线程;
- 操作系统尝试创建一个新的 native 线程,并为其分配内存;
- 如果操作系统的虚拟内存已耗尽,或是受到 32 位进程的地址空间限制,操作系统就会拒绝本次 native 内存分配;
- JVM 将抛出 java.lang.OutOfMemoryError:Unableto createnewnativethread 错误 。
- 想办法降低程序中创建线程的数量,分析应用是否真的需要创建这么多线程
- 如果确实需要创建很多线程,调高 OS 层面的线程最大数:执行 ulimia-a 查看最大线程数限制,使用 ulimit-u xxx 调整最大线程数限制
推荐阅读
- 产品风险评估报告怎么写 淘宝店铺风险分析
- 再见HTML ! 用纯Python就能写一个漂亮的网页
- 纯CSS实现轮播图
- 假设你的文案压根没人看
- 如何写出转化率高的爆款文案
- 写在最美的季节,送给径山的冬日散文诗
- 分析2.5万篇博客后,来看看后端程序员每天都在写什么
- 淘宝卖家给买家的好评怎么写 淘宝店铺好评怎么写
- 淘宝申诉说明范例 淘宝侵权申诉内容怎么写
- Ubuntu18.04部署django3.x