JVM专题 1:java直接内存DirectByteBuffer与垃圾回收

先上test代码

public class DirectMemoryTest {

public static void main(String[] args) {

ByteBuffer buffer =null;

try {

long startTime=System.currentTimeMillis();

for(int i=0;i<100;i++){

buffer = ByteBuffer.allocateDirect(1024 *1024 *250);

//clean(buffer);

            }

long endTime=System.currentTimeMillis();

System.out.println("程序运行时间: "+(endTime-startTime)+"ms");

//System.out.println(null+"");

        }catch (Exception e) {

e.printStackTrace();

}

}

public static void clean(final ByteBuffer byteBuffer) {

if (byteBuffer.isDirect()) {

((DirectBuffer)byteBuffer).cleaner().clean();

}

}

}

运行使用的jvm参数 打印gc日志,直接内存设置最大1G

-XX:+PrintGCDetails -XX:+UseConcMarkSweepGC  -XX:MaxDirectMemorySize=1024M

不调用clean()方法的时候,会频繁的发生由于system.gc()造成的full gc,此时老年代并未使用很多

[Full GC (System.gc()) [CMS: 0K->657K(87424K), 0.0104483 secs] 2801K->657K(126720K), [Metaspace: 3390K->3390K(1056768K)], 0.0105395 secs] [Times: user=0.00 sys=0.02, real=0.01 secs] 
[Full GC (System.gc()) [CMS: 657K->652K(87424K), 0.0054286 secs] 658K->652K(126848K), [Metaspace: 3391K->3391K(1056768K)], 0.0055050 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (System.gc()) [CMS: 652K->652K(87424K), 0.0048721 secs] 1354K->652K(126848K), [Metaspace: 3391K->3391K(1056768K)], 0.0049353 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (System.gc()) [CMS: 652K->652K(87424K), 0.0055415 secs] 652K->652K(126848K), [Metaspace: 3391K->3391K(1056768K)], 0.0056139 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

当调用了clean()方法的时候,却不会发生任何一次fullGC

这是为什么呢?继续上代码,DirectByteBuffer初始化的时候,内部会显示调用System.gc();


image.png

image.png

关键就在这里,显示调用System.gc(),当jvm发现直接内存MaxDirectMemorySize=1024M所剩无几的时候,就会触发fullGC。
现在大概是1G直接内存,每次申请250M,可以发现3个循环之后会触发一次fullgc.如果每次申请的大小继续增大,比如400
m,可以发现2个循环之后就会fullgc。

这也就解释了,为什么当调用了clean()方法的时候,却不会发生任何一次fullGC,因为每一次都会手动的释放内存,jvm即使接到

System.gc()命令,但是认为没必要进行gc,就不会触发。

解决:1.手动释放 ((DirectBuffer)byteBuffer).cleaner().clean()
2.禁用System.gc(),参数 -XX:-+DisableExplicitGC 有可能会导致,直接内存得不到回收,发生OOM(此时,只有发生堆内存回收的时候,才会顺带的回收直接内存)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容