java.lang.OutOfMemoryError:超出了GC开销限制

问题

我在一个程序中收到此错误,该程序创建了几个(数十万)HashMap对象,每个对象带有几个(15-20)文本条目。在提交到数据库之前,必须收集这些字符串(不会分解成较小的数量)。

根据Sun的说法,错误发生在"如果在垃圾收集中花费太多时间:如果超过98%的总时间花在垃圾收集上并且不到2%的堆被恢复,则将抛出OutOfMemoryError。 "。

显然,可以使用命令行将参数传递给JVM for

  • 通过"-Xmx1024m"(或更多)增加堆大小,或
  • 通过"-XX:-UseGCOverheadLimit"完全禁用错误检查。

第一种方法工作正常,第二种方法在另一个java.lang.OutOfMemoryError中结束,这次是关于堆的。

那么,问题:对于特定的用例(即几个小的HashMap对象),是否有任何编程替代方案?例如,如果我使用HashMap clear()方法,问题就会消失,但HashMap中存储的数据也会消失! :-)

这个问题也在arelated topic in StackOverflow.中讨论过


#1 热门回答(154 赞)

你基本上没有内存来顺利运行这个过程。想到的选项:

  • 像你提到的那样指定更多内存,首先尝试介于-Xmx512m之间的内容
  • 尽可能使用较小批量的HashMap对象进行处理
  • 如果你有很多重复的字符串,在将它们放入HashMap之前对它们使用String.intern()
  • 使用HashMap(int initialCapacity,float loadFactor)构造函数来调整你的案例

#2 热门回答(59 赞)

以下对我有用。只需添加以下代码段:

dexOptions {
        javaMaxHeapSize "4g"
}

致你的build.gradle

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.1'

    defaultConfig {
        applicationId "yourpackage"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"

        multiDexEnabled true
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    packagingOptions {

    }

    dexOptions {
        javaMaxHeapSize "4g"
    }
}

#3 热门回答(40 赞)

@takrl:此选项的默认设置为:

java -XX:+UseConcMarkSweepGC

这意味着,默认情况下此选项不活动。所以当你说你使用选项"+XX:UseConcMarkSweepGC"时,我假设你使用的是这种语法:

java -XX:+UseConcMarkSweepGC

这意味着你明确激活了此选项。有关正确的语法和默认设置Java HotSpot VM Options @ thisdocument