Может ли этот код Scala использовать меньше памяти? - PullRequest
5 голосов
/ 20 августа 2011

Рассмотрим следующий эталонный набор:

import scala.collection.immutable._

object SetTest extends App {
  def time[a](f: => a): (a,Double) = {
    val start = System.nanoTime()
    val result: a = f
    val end = System.nanoTime()
    (result, 1e-9*(end-start))
  }

  for (n <- List(1000000,10000000)) {
    println("n = %d".format(n))
    val (s2,t2) = time((Set() ++ (1 to n)).sum)
    println("sum %d, time %g".format(s2,t2))
  }
}

Компиляция и запуск производит

tile:scalafab% scala SetTest
n = 1000000
sum 1784293664, time 0.982045
n = 10000000
Exception in thread "Poller SunPKCS11-Darwin" java.lang.OutOfMemoryError: Java heap space
...

Т.е., Scala не может представить набор из 10 миллионов Ints на машине с 8 ГБ памяти. Это ожидаемое поведение? Есть ли способ уменьшить объем памяти?

Ответы [ 3 ]

10 голосов
/ 20 августа 2011

Общие неизменяемые наборы do занимают много памяти. По умолчанию используется только 256 Мп кучи, что оставляет только 26 байт на объект. Хеш-код для неизменяемых наборов обычно занимает от одного до двухсот байтов на объект дополнительно около 60 байтов на элемент. Если вы добавите -J-Xmx2G в командной строке, чтобы увеличить пространство кучи до 2G, все будет в порядке.

(Этот уровень издержек является, например, одной из причин, по которой существуют битовые наборы.)

3 голосов
/ 20 августа 2011

Я не настолько знаком со Scala, но вот что, по-моему, происходит:

Прежде всего, целые числа хранятся в куче (как и должно быть, поскольку структура данных хранится в куче). Таким образом, мы говорим о доступной памяти кучи, а не о стеке памяти вообще (просто чтобы прояснить обоснованность того, что я собираюсь сказать дальше).

Настоящим фактом является то, что размер кучи Java по умолчанию довольно мал - я считаю, что он составляет всего 128 мегабайт (это, вероятно, действительно старое число, но дело в том, что число существует, и оно довольно мало ).

Значит, дело не в том, что ваша программа использует слишком много памяти, а в том, что Java просто не дает вам достаточно в первую очередь. Однако есть решение: минимальный и максимальный размеры кучи можно установить с помощью параметров командной строки -Xms и -Xmx. Их можно использовать как:

java -Xms32m -Xmx128m MyClass   (starts MyClass with a minimum heap of 32 megabytes, maximum of 128 megabytes)

java -Xms1g -Xmx3g MyClass (executes MyClass with a minimum heap of 1 gigabytes, maximum of 3 gigabytes)

Если вы используете IDE, там, вероятно, есть опции для изменения размера кучи.

0 голосов
/ 21 августа 2011

Это всегда должно быть переполнено.Хранение таких больших значений в этом случае не требуется.Если вы хотите суммировать, используйте итератор или диапазон.

val (s2,t2) = time( (1 to n).sum)

Приведенная выше строка завершается за секунду без переполнения.

Вы всегда можете увеличить выделение памяти, используя другие ответы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...