spire icon indicating copy to clipboard operation
spire copied to clipboard

High unmanaged memory use for N:Fractional

Open glorat opened this issue 6 years ago • 5 comments

scala 2.12.10 spire 0.14.1 JRE - tested both on JRE8 and JRE11 After hours tracking down a memory spike (that was enough to tip over to an OOM at the JVM process level), I distilled the issue to this:

  def identity[N:Fractional](a:N): N = a

On first call to this function, memory in the JVM (not managed memory) spikes by about 450MB of RAM. Reproducible with code like

  def main(args: Array[String]) {
    val myOther = identity[Double](1.0)
  }

Simply set the debugger on that line and when trying to step in, the process memory spikes. I assume the JIT is processing this. Apart from top etc. the memory spike can be captured by jcmd while stepping over that line. For some reason, memory gets allocated here:

  // -                    Thread (reserved=394152KB, committed=394152KB)
  //                            (thread #33)
  //                            (stack: reserved=32768KB, committed=32768KB)
  //                            (malloc=99KB #170)
  //                            (arena=361285KB #65)

once the line is completed, all that arena memory gets freed.

With my process only generally needing 200MB of heap memory, having to reserve an extra 450MB is sizeable costly overhead. My alternatives are to unwind the neat typeclasses and copy/paste explicit implementations for Rational vs Double.

In fairness, I don't think this is a Spire issue but probably something at the Scala or JVM level but I'm hoping those familiar with Spire internals and the use of all these generics can distil this into why this is happening any maybe raise it upstream.

glorat avatar Jan 30 '20 14:01 glorat

Any method calls on Fractional[N] also trigger the same memory spike behaviour

glorat avatar Feb 02 '20 03:02 glorat

I guess that depending on Fractional pulls a lot of stuff from Spire and that's the spike you're looking at.

Can I ask you what you're using Fractional for? It's a jack-of-all-trades class that's not very principled, and its functionality will probably be split between different type classes in a future release.

denisrosset avatar Feb 04 '20 22:02 denisrosset

Thanks for your reply

I had written a few interpolation routines that are able to operate either on Rational or on Double - and in different cases in my code (depending on what precision was needed), I'd use either one of those. So that I didn't have to copy/paste the same code, it was convenient to have those methods take N:Fractional instead.

If there was another way to write this generic Rational or Double code, I'd take it. For now, I've just copy/pasted out the methods.

glorat avatar Feb 05 '20 01:02 glorat

The problem is likely that Fractional pulls a significant fraction of the Spire library. You may have better luck using Field and Order for example, if they provide what you need.

denisrosset avatar Feb 07 '20 21:02 denisrosset

The problem is likely that Fractional pulls a significant fraction of the Spire library. You may have better luck using Field and Order for example, if they provide what you need.

Thanks so much for this suggestion! In 5 minutes testing, some parsing code I have compiles successfully with N:Field:Order. The key piece interpolation of code doesn't compile because toDouble (understandably) doesn't exist but otherwise seems it will compile (I use various maths operators, isZero, comparators - all seem supported).

I have other more urgent issues to deal with for now (since I've worked around all this by copy/paste) but hope to give this a try and reprofile some day when I have time.

glorat avatar Feb 08 '20 14:02 glorat