JAVA NIO 内存泄露

写NIO程序经常使用ByteBuffer来读取或者写入数据,那么使用ByteBuffer.allocate(capability)还是使用ByteBuffer.allocteDirect(capability)来分配缓存了?第一种方式是分配JVM堆内存,属于GC管辖范围,由于需要拷贝所以速度相对较慢;第二种方式是分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快。

我们肯定想选择比较快的,但问题是直接内存不属于GC管辖范围,需要弄清楚这部分内存如何管理,否则造成内存泄露就麻烦了。本地内存在JAVA中有一个对应的包装类DirectByteBuffer,该类属于Java类,适当的时候会被GC回收,当它被回收前会调用本地方法把直接内存给释放了,所以本地内存可以随DirectByteBuffer对象被回收而自动回收,貌似没有问题;但如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象们就不会被回收,这时候堆内存充足,但本地内存可能已经使用光了,再次尝试分配本地内存就会出现OutOfMemoryError,那程序就直接崩溃了。

有没有解决方案?自动释放不靠谱,我们是否可以手动释放本地内存,把握主动权?果然DirectByteBuffer持有一个Cleaner对象,该对象有一个clean()方法可用于释放本地内存,所以需要的时候我们可以调用这个方法手动释放本地内存。

以下代码与测试场景帮助理解与证实以上描述。

代码1:

package com.stevex.app.nio;

import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;

public class DirectByteBufferTest {
	public static void main(String[] args) throws InterruptedException{
	        //分配128MB直接内存
		ByteBuffer bb = ByteBuffer.allocateDirect(1024*1024*128);

		TimeUnit.SECONDS.sleep(10);
		System.out.println("ok");
	}

}

测试用例1:设置JVM参数-Xmx100m,运行异常,因为如果没设置-XX:MaxDirectMemorySize,则默认与-Xmx参数值相同,分配128M直接内存超出限制范围。

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
	at java.nio.Bits.reserveMemory(Bits.java:658)
	at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
	at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
	at com.stevex.app.nio.DirectByteBufferTest.main(DirectByteBufferTest.java:8)

测试用例2:设置JVM参数-Xmx256m,运行正常,因为128M小于256M,属于范围内分配。

ok

测试用例3:设置JVM参数-Xmx256m -XX:MaxDirectMemorySize=100M,运行异常,分配的直接内存128M超过限定的100M。

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
	at java.nio.Bits.reserveMemory(Bits.java:658)
	at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
	at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
	at com.stevex.app.nio.DirectByteBufferTest.main(DirectByteBufferTest.java:8)


代码2:

package com.stevex.app.nio;

import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import sun.nio.ch.DirectBuffer;

public class DirectByteBufferTest {
	public static void main(String[] args) throws InterruptedException{
		//分配512MB直接缓存
		ByteBuffer bb = ByteBuffer.allocateDirect(1024*1024*512);

		TimeUnit.SECONDS.sleep(10);

		//清除直接缓存
		((DirectBuffer)bb).cleaner().clean();

		TimeUnit.SECONDS.sleep(10);

		System.out.println("ok");
	}

}

测试用例4:设置JVM参数-Xmx768m,运行程序观察内存使用变化,会发现clean()后内存马上下降,说明使用clean()方法能有效及时回收直接缓存。

时间: 2024-08-02 02:49:58

JAVA NIO 内存泄露的相关文章

java的内存泄露是如何发生的,如何避免和发现?

java的垃圾回收与内存泄露的关系:[新手可忽略不影响继续学习] (视频下载) (全部书籍) 马克-to-win:上一节讲了,(i)对象被置成null.(ii)局部对象(无需置成null)当程序运行到右大括号.(iii)匿名对象刚用完,垃圾回收线程就早早晚晚都能把它过去占的内存给回收了.这么说,java中难道就没有c++的内存泄露的问题了吗?(内存泄露的定义就是: 咱自己程序不用的内存,系统本应回收但由于各种原因却没有回收成功)马克-to-win:答案: 错,java中有内存泄露.下面我们就通过

java的内存泄露

java的内存泄露 来源:http://www.sxt.cn/Java_jQuery_in_action/The_operation_of_memory_leakage_in_development.html 在实际开发中,经常会造成系统的崩溃.如下这些操作我们应该注意这些使用场景. 创建大量无用对象: 比如,我们在需要大量拼接字符串时,使用了String而不是StringBuilder. String str = ""; for (int i = 0; i < 10000; i

JAVA NIO 内存映射(转载)

原文地址:http://blog.csdn.net/fcbayernmunchen/article/details/8635427 Java类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原理. 在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数 read().write() ,此时调用此函数的进程(在JAVA中即java进程)由当

Java中内存泄露及垃圾回收机制

3 垃圾回收机制 3.1 什么是垃圾 垃圾,内存中的垃圾,即内存中已无效但又无法自动释放的空间.在Java语言中,没有引用句柄指向的类对象最容易成为垃圾.,产生垃圾的情况有很多,主要有以下3种: (1)       超出对象的引用句柄的作用域时,这个引用句柄引用的对象就变成垃圾. 例: { Person p1 = new Person(); …… } 引用句柄p1的作用域是从定义到“}”处,执行完这对大括号中的所有代码后,产生的Person对象就会变成垃圾,因为引用这个对象的句柄p1已超过其作用

Java NIO内存映射---上G大文件处理

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了java中内存映射的原理及过程,与传统IO进行了对比,最后,用实例说明了结果. 一.java中的内存映射IO和内存映射文件是什么? 内存映射文件非常特别,它允许Java程序直接从内存中读取文件内容,通过将整个或部分文件映射到内存,由操作系统来处理加载请求和写入文件,应用只需要和内存打交道,这使得IO操作非常快.加载内存映射文件所使用的内存在Java堆区之外.Java编程语言

Java NIO内存映射---上G大文件处理(转)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了java中内存映射的原理及过程,与传统IO进行了对比,最后,用实例说明了结果. 一.java中的内存映射IO和内存映射文件是什么? 内存映射文件非常特别,它允许Java程序直接从内存中读取文件内容,通过将整个或部分文件映射到内存,由操作系统来处理加载请求和写入文件,应用只需要和内存打交道,这使得IO操作非常快.加载内存映射文件所使用的内存在Java堆区之外.Java编程语言

java之内存泄露

一.过期引用导致的内存泄露 注意:当对象不使用后将对象设置为null,这个时候虚拟机不一定释放该内存,至于什么时候释放由垃圾回收算法确定. 当对象不在使用时,而不回收有可能出现内存泄露的问题.在Effective Java里面有一条建议,消除过期的对象引用. 实例:JDK中栈的内存优化问题 1.消除过期对象引用的原因(出现内存泄露的原因):随着栈的增加,然后再收缩,从栈中出来的对象将不会被回收,即使程序不在引用这些对象. 因为,在栈的内部维护着这些对象的过期引用(过期引用就是永远不会被解除的引用

JAVA简单内存泄露分析及解决

一.问题产生    项目采用Tomcat6.0为服务器,数据库为mysql5.1,数据库持久层为hibernate3.0,以springMVC3.0为框架,项目开发完成后,上线前夕进行稳定性拷机,测试数据为插入4条/S,更新4条/S,访问300次/S,前期运行速度顺畅,三天后就开始运行缓慢,访问量达到1500W次后以抛出Java heap space结束.二.问题分析    1.前期分析为连接池内存溢出,期间优化了连接池参数,调整了tomcat线程参数,替换数据库连接池,问题依旧    2.看来

【转】Java学习---内存泄露与溢出的区别

Java内存泄露与溢出的区别 Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内存资源耗尽): 而Java内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出. 内存溢出类似数组越届,超出你能存储的数据的上限 内存泄漏,就是内存使用完毕后,不能释放回收重新使用 Java内存泄露与溢出的区别 内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出. Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(