Scala 调试lmdbjni访问冲突的下一步

Scala 调试lmdbjni访问冲突的下一步,scala,java-native-interface,lmdb,Scala,Java Native Interface,Lmdb,我正在使用LMDBjni的这个分支:来 在scala中形成一个中型数据库项目的后端 我在这个LMDB的JNI代码中遇到了一个异常\u访问\u冲突(0xc0000005),我想知道是否有明显的错误,或者调试的下一步应该是什么。我不太确定我在寻找什么,所以我将尽可能多地列出正在发生的事情的信息,并希望这些症状对某人有意义 访问冲突发生在具有单个键映射到单个8字节值的数据库中,大约在对该数据库进行第4000次访问时(每次运行的确切数字似乎相同),这表明这是一个确定性问题 我相信我一次只有一个线程访问数

我正在使用LMDBjni的这个分支:来 在scala中形成一个中型数据库项目的后端

我在这个LMDB的JNI代码中遇到了一个
异常\u访问\u冲突(0xc0000005)
,我想知道是否有明显的错误,或者调试的下一步应该是什么。我不太确定我在寻找什么,所以我将尽可能多地列出正在发生的事情的信息,并希望这些症状对某人有意义

访问冲突发生在具有单个键映射到单个8字节值的数据库中,大约在对该数据库进行第4000次访问时(每次运行的确切数字似乎相同),这表明这是一个确定性问题

我相信我一次只有一个线程访问数据库,而且无论如何,在我的理解中,由于操作是封装在事务中的,并发访问无论如何都不重要

通过查看堆栈跟踪和打印值,问题来自我为构建事务编写的这个通用构造

导致问题的代码在这里,崩溃发生在标记的
db.get()
调用中:

def transactionalGetAndSet[A](
    key: Key,
    db: Database
)(
    compute: A => LMDBEither[A]
 )(
    implicit sa: Storeable[A], 
    env: Env
 ): LMDBEither[A] = {
    import org.fusesource.lmdbjni.Transaction

    // get a new transaction
    val tx: Transaction = instance.env.createWriteTransaction()

    println("tx = " + tx + " id = " + tx.getId)
    // get the key as an Array[Byte]. This is done by converting the key to a base64 string then converting that to bytes (so arbitary objects can be made into keys)
    val k = key.render
    println("Key = " + key + " Rendered = " + new String(k))
    // instantiate a result value, so there is something if it fails
    var res: LMDBEither[A] = NoResult.left // initialise the result as a failure to begin with
    try {
        res = for { // This for construction chains together operations that return LMDBEithers into one LMDBEither
          bytes <- LMDBEither(db.get(tx, k)) // error occurs in this Database.get() call
          _ = println("bytes = " + bytes)
          a <- sa.fromBytes(safeRetrieve(bytes)) // sa is effectively an unmarshaller/unmarshaller object which converts Vector[Byte] => LMDBEither[A]
          _ = println("a = " + a)
          res <- compute(a) // get the next value for the value at the key
          _ = println("res = " + res)
          _ <- LMDBEither(db.put(tx, k, sa.toBytes(res).toArray))
        } yield a // effectively, if all these steps worked, res == Right(a)
        res // return the result
    } finally {
      // Make sure you either commit or rollback to avoid resource leaks.
      if (res.isRight) tx.commit() // if the result is not an error (ie Either.isRight is true)
      else tx.abort()
      tx.close()
    }
  }
据我所知,这不会修改存储阵列的内存(LMDB的受保护内存)

碰撞前打印的值(包括碰撞)如下所示:

  private def safeRetrieve(bytes: Array[Byte]): Vector[Byte]  =       
  Option(bytes).fold(Vector[Byte]()){ // if the array is null, convert to an empty vector, otherwise call the array's wrapper's vector
      arr =>
        println("Vector = " + arr.toVector)
        arr.toVector
  }
tx = org.fusesource.lmdbjni.Transaction@391cec1f id = 15104
Key = Vector(Objects) Rendered = 84507411390877848991196161
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000018002453f,     pid=10220, tid=7268
#
# JRE version: Java(TM) SE Runtime Environment (8.0_60-b27) (build 1.8.0_60-b27)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.60-b23 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [lmdbjni-64-0-7710432736670562378.4+0x2453f]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\dev\PartIIProject\hs_err_pid10220.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
这是mdb_get()失败的更多证据。 参考文件的完整内容如下所示:


再一次,我非常感谢有这么小的机会,任何人都能为我指明正确的方向。接下来我应该采取什么措施?

我想我应该澄清一下,我不希望看到魔杖的答案,但我非常感谢您帮助我了解访问冲突的含义、常见原因,以及其他更有经验使用LMDB+JVM语言的人是否也有类似的问题,等等,“访问冲突”表示程序试图访问一些无效的内存位置。通常这意味着直接内存损坏或试图使用已释放的指针。如果您使用JNI,那么LMDB必须用某种基于VM的语言实现,在这种语言中,两种错误都很可能发生。然而,这也可能是LMDB JNI中的一个bug,或者是由于错误使用它而引入的bug。如何帮助你真的很难提出建议。最好的方法可能是制作并发布一个非常小的文件,这样每个人都可以复制和调试这个问题。一个可能的原因是LMDB环境/db在不同的线程中关闭。正在进行的读/写操作将访问无效的内存位置。