欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MappedByteBuffer强制释放后读取引发jvm crash

程序员文章站 2022-06-07 19:32:28
...

 

这几天使用MappedByteBuffer对系统进行了实现,在压测过程中发现启动多个group订阅时服务端会发生jvm crash ,排查后找到了原因,记录一下。

 

部分信息如下:

#

# A fatal error has been detected by the Java Runtime Environment:

#

#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x01b8d4d7, pid=10236, tid=8452

#

# JRE version: 6.0_18-b02

# Java VM: Java HotSpot(TM) Client VM (16.0-b09 mixed mode, sharing windows-x86 )

# Problematic frame:

# J  java.nio.DirectByteBuffer.get(I)B

#

# An error report file with more information is saved as:

# D:\workspace_new\metamorphosis\metamorphosis-server\hs_err_pid10236.log

#

# If you would like to submit a bug report, please visit:

#   http://java.sun.com/webapps/bugreport/crash.jsp

#

 

原因是在MappedByteBuffer释放后再对它进行读操作的话就会引发这个crash,在并发情况下很容易正在释放时另一个线程正开始读取,于是crash就发生了。下面这个测试代码可以重现:

 

@Test

public void unmapAndRead()throws Exception {

  File file =new File("unmapAndRead.txt");

  FileChannel fileChannel =new RandomAccessFile(file,"rw").getChannel();

  MappedByteBuffer buf = fileChannel.map(MapMode.READ_WRITE, 0, 4096);

  buf.putInt(5);

  buf.force();

  this.unmap(buf);

  buf.get(2);//Crash occur

}

 

void unmap(finalMappedByteBuffer mappedByteBuffer) {

  try {

    if (mappedByteBuffer ==null) {

    return;

  }

  mappedByteBuffer.force();

  AccessController.doPrivileged(new PrivilegedAction<Object>() {

  @Override

  public Object run() {

    try {

       Method getCleanerMethod =      mappedByteBuffer.getClass().getMethod("cleaner",new Class[0]);

       getCleanerMethod.setAccessible(true);

       sun.misc.Cleaner cleaner =

       (sun.misc.Cleaner)getCleanerMethod.invoke(mappedByteBuffer,new Object[0]);

       cleaner.clean();

    }

    catch (Exception e) {

       e.printStackTrace();

    }

    return null;

   }

  });

 

 }

catch (Exception e) {

   e.printStackTrace();

}

}