Kesalahan java.lang.OutOfMemoryError: Batas overhead GC terlampaui


805

Saya mendapatkan pesan kesalahan ini saat saya menjalankan tes JUnit saya:

java.lang.OutOfMemoryError: GC overhead limit exceeded

Saya tahu apa itu OutOfMemoryError itu, tetapi apa artinya batas atas GC? Bagaimana saya bisa memecahkan masalah ini?


16
Ini terdengar sangat menarik. Saya akan senang jika seseorang dapat memposting beberapa kode yang menghasilkan ini.
Buhb

1
Saya hanya menemukan masalah, yang menyebabkan terlalu banyak penggunaan memori, mendekati batas tumpukan. Solusi sederhana bisa saja dengan memberikan lebih banyak Heap-memory ke Java-Engine (-Xmx) tetapi ini hanya membantu, jika aplikasi membutuhkan persis banyak memori, seperti heap-limit sebelum ditetapkan.
Mnementh

1
@Mnementh saya telah memberikan jawaban di sini untuk memeriksa apakah itu membantu stackoverflow.com/questions/11091516/…
lulu

16
@SimonKuang Perhatikan bahwa ada beberapa OutOfMemoryErrorskenario yang meningkatkan tumpukan bukan solusi yang valid: kehabisan utas asli dan kehabisan perm gen (yang terpisah dari tumpukan) adalah dua contoh. Hati-hati membuat pernyataan yang terlalu luas tentang OutOfMemoryErrors; ada serangkaian hal yang tak terduga yang bisa menyebabkannya.
Tim

3
Bagaimana Anda mengatasi masalah ini ??
Thorsten Niehues

Jawaban:


764

Pesan ini berarti bahwa karena suatu alasan pemulung mengambil banyak waktu (secara default 98% dari semua waktu CPU dari proses) dan memulihkan sedikit memori dalam setiap proses (secara default 2% dari tumpukan).

Ini secara efektif berarti bahwa program Anda berhenti melakukan kemajuan apa pun dan sibuk hanya menjalankan pengumpulan sampah setiap saat.

Untuk mencegah aplikasi Anda menghabiskan waktu CPU tanpa menyelesaikan apa pun, JVM melempar ini Error sehingga Anda memiliki kesempatan untuk mendiagnosis masalah.

Kasus-kasus langka di mana saya melihat ini terjadi adalah ketika beberapa kode menciptakan banyak objek sementara dan banyak objek yang direferensikan dengan lemah di lingkungan yang sudah sangat dibatasi oleh memori.

Lihatlah panduan penyetelan Java GC, yang tersedia untuk berbagai versi Java dan berisi bagian tentang masalah khusus ini:


9
Apakah benar untuk meringkas jawaban Anda sebagai berikut: "Ini seperti kesalahan 'Keluar dari Java Heap space'. Berikan lebih banyak memori dengan -Xmx." ?
Tim Cooper

58
@ Tim: Tidak, itu tidak benar. Meskipun memberi lebih banyak memori dapat mengurangi masalah, Anda juga harus melihat kode Anda dan melihat mengapa ia menghasilkan jumlah sampah itu dan mengapa kode Anda meleset tepat di bawah tanda "kehabisan memori". Ini sering merupakan tanda kode rusak.
Joachim Sauer

8
Terima kasih, sepertinya Oracle tidak begitu baik dalam migrasi data, mereka memutuskan tautan.
Joachim Sauer

151
Anda membuat saya di "Terima kasih, sepertinya Oracle sebenarnya tidak sebagus itu"
Rob Grant

3
@Guus: jika beberapa aplikasi berjalan dalam JVM yang sama, maka ya, mereka dapat dengan mudah saling mempengaruhi. Akan sulit untuk mengatakan mana yang salah tingkah. Memisahkan aplikasi menjadi JVM yang berbeda mungkin merupakan solusi termudah.
Joachim Sauer

215

Mengutip dari artikel Oracle "Java SE 6 HotSpot [tm] Tuning Koleksi Mesin Virtual" :

Waktu dan OutOfMemoryError GC Berlebihan

Kolektor paralel akan melempar OutOfMemoryError jika terlalu banyak waktu dihabiskan dalam pengumpulan sampah: jika lebih dari 98% dari total waktu dihabiskan dalam pengumpulan sampah dan kurang dari 2% dari tumpukan dipulihkan, OutOfMemoryError akan dilemparkan. Fitur ini dirancang untuk mencegah aplikasi berjalan untuk jangka waktu yang lama sementara membuat sedikit atau tidak ada kemajuan karena tumpukan terlalu kecil. Jika perlu, fitur ini dapat dinonaktifkan dengan menambahkan opsi -XX:-UseGCOverheadLimitke baris perintah.

EDIT: sepertinya seseorang dapat mengetik lebih cepat dari saya :)


87
"Anda dapat mematikan ini ..." tetapi OP kemungkinan besar tidak harus melakukan ini.
Stephen C

2
Bisakah Anda memberi tahu saya perbedaan antara "-XX" dan "-Xmx"? Saya bisa mematikannya menggunakan opsi "-Xmx" juga.
Susheel Javadi

19
Membalas komentar yang sangat lama di sini, tapi ... @Bart Di -XX:awal beberapa opsi baris perintah adalah flag of sort yang menunjukkan bahwa opsi ini sangat spesifik-VM dan tidak stabil (dapat berubah tanpa pemberitahuan di versi mendatang). Bagaimanapun, -XX:-UseGCOverheadLimitflag memberitahu VM untuk menonaktifkan pengecekan batas overhead GC (sebenarnya "mematikannya"), sedangkan -Xmxperintah Anda hanya meningkatkan heap. Dalam kasus terakhir pemeriksaan overhead GC masih berjalan , sepertinya tumpukan yang lebih besar memecahkan masalah meronta-ronta GC dalam kasus Anda (ini tidak akan selalu membantu).
Andrzej Doyle

1
Dalam aplikasi saya (membaca file Excel besar di Talend) ini tidak berhasil dan dari penjelasan pengguna lain saya mengerti mengapa. Ini hanya menonaktifkan kesalahan tetapi masalahnya tetap ada dan aplikasi Anda hanya akan menghabiskan sebagian besar waktunya menangani GC. Server kami memiliki banyak RAM, jadi saya menggunakan saran dari Vitalii untuk meningkatkan ukuran tumpukan.
RobbZ

Anda akhirnya akan mendapatkan kesalahan ini jika aplikasi Anda intensif data, membersihkan memori dan menghindari kebocoran data adalah jalan keluar terbaik - tetapi membutuhkan waktu.
Pievis

89

Jika Anda yakin tidak ada kebocoran memori dalam program Anda, cobalah untuk:

  1. Tambah ukuran heap, misalnya -Xmx1g .
  2. Aktifkan pengumpul jeda rendah bersamaan -XX:+UseConcMarkSweepGC .
  3. Gunakan kembali objek yang ada bila memungkinkan untuk menghemat memori.

Jika perlu, pemeriksaan batas dapat dinonaktifkan dengan menambahkan opsi -XX:-UseGCOverheadLimitke baris perintah.


9
Saya tidak setuju dengan saran ketiga. Menggunakan kembali objek yang ada tidak menghemat memori (jangan bocor benda lama menghemat memori :-) Selain itu "menggunakan kembali objek yang ada" adalah praktik untuk mengurangi tekanan GC. Tetapi ini BUKAN selalu merupakan ide yang baik: dengan GC modern, kita harus menghindari situasi di mana benda-benda lama memiliki yang baru karena dapat mematahkan beberapa asumsi lokalitas ...
mcoolive

@ mcoolive: Untuk contoh yang agak dibuat-buat, lihat komentar untuk menjawab stackoverflow.com/a/5640498/4178262 di bawah ini; membuat Listobjek di dalam loop menyebabkan GC disebut 39 kali, bukan 22 kali.
Mark Stewart

45

Biasanya kodenya. Berikut ini contoh sederhana:

import java.util.*;

public class GarbageCollector {

    public static void main(String... args) {

        System.out.printf("Testing...%n");
        List<Double> list = new ArrayList<Double>();
        for (int outer = 0; outer < 10000; outer++) {

            // list = new ArrayList<Double>(10000); // BAD
            // list = new ArrayList<Double>(); // WORSE
            list.clear(); // BETTER

            for (int inner = 0; inner < 10000; inner++) {
                list.add(Math.random());
            }

            if (outer % 1000 == 0) {
                System.out.printf("Outer loop at %d%n", outer);
            }

        }
        System.out.printf("Done.%n");
    }
}

Menggunakan Java 1.6.0_24-b07 pada Windows 7 32 bit.

java -Xloggc:gc.log GarbageCollector

Kemudian lihat gc.log

  • Dipicu 444 kali menggunakan metode BAD
  • Dipicu 666 kali menggunakan metode WORSE
  • Dipicu 354 kali menggunakan metode LEBIH BAIK

Sekarang diberikan, ini bukan tes terbaik atau desain terbaik tetapi ketika dihadapkan pada situasi di mana Anda tidak punya pilihan selain menerapkan loop seperti itu atau ketika berhadapan dengan kode yang ada yang berperilaku buruk, memilih untuk menggunakan kembali objek daripada membuat yang baru dapat mengurangi berapa kali pengumpul sampah menghalangi ...


12
Tolong jelaskan: Ketika Anda mengatakan "Dipicu n kali", apakah itu berarti bahwa GC reguler terjadi n kali, atau bahwa kesalahan "batas overhead GC terlampaui" yang dilaporkan oleh OP terjadi n kali?
Jon Schneider

Saya baru saja diuji menggunakan java 1.8.0_91 dan tidak pernah mendapat kesalahan / pengecualian, dan "Dipicu n kali" adalah dari menghitung jumlah baris dalam gc.logfile. Tes saya menunjukkan jauh lebih sedikit kali secara keseluruhan, tetapi waktu "Pemicu" paling sedikit untuk LEBIH BAIK, dan sekarang, BAD "lebih buruk" daripada TERBURUK sekarang. Hitungan saya: BURUK: 26, LEBIH BURUK: 22, LEBIH BAIK 21.
Mark Stewart

Saya baru saja menambahkan modifikasi "WORST_YET" di mana saya mendefinisikan List<Double> listdalam loop luar daripada sebelum loop luar, dan Memicu 39 koleksi sampah.
Mark Stewart

36

Penyebab kesalahan menurut Platform Java [8], Panduan Pemecahan Masalah Edisi Standar : (penekanan dan penambahan saluran ditambahkan)

[...] "Batas overhead GC terlampaui" menunjukkan bahwa pemungut sampah berjalan sepanjang waktu dan program Java membuat kemajuan yang sangat lambat.

Setelah pengumpulan sampah, jika proses Java menghabiskan lebih dari sekitar 98% waktunya untuk mengumpulkan sampah dan jika memulihkan kurang dari 2% dari timbunan dan telah melakukan sejauh ini 5 terakhir (kompilasi waktu konstan) berturut-turut sampah koleksi, maka java.lang.OutOfMemoryErrordilemparkan. [...]

  1. Tambah ukuran tumpukan jika tumpukan saat ini tidak cukup.
  2. Jika Anda masih mendapatkan kesalahan ini setelah menambah memori tumpukan, gunakan alat profil memori seperti MAT (Memory analyzer tool), Visual VM dll dan perbaiki kebocoran memori.
  3. Tingkatkan versi JDK ke versi terbaru (1.8.x) atau setidaknya 1.7.x dan gunakan algoritma G1GC. . Sasaran throughput untuk G1 GC adalah waktu aplikasi 90 persen dan waktu pengumpulan sampah 10 persen
  4. Selain mengatur memori tumpukan dengan - Xms1g -Xmx2g, coba

    -XX:+UseG1GC -XX:G1HeapRegionSize=n -XX:MaxGCPauseMillis=m  
    -XX:ParallelGCThreads=n -XX:ConcGCThreads=n

Lihat beberapa pertanyaan terkait terkait G1GC


29

Cukup tambahkan ukuran tumpukan sedikit dengan mengatur opsi ini di

Jalankan → Jalankan Konfigurasi → Argumen → Argumen VM

-Xms1024M -Xmx2048M

Xms - untuk batas minimum

Xmx - untuk batas maksimum


2
Aplikasi android tidak memiliki argumentstab ... apa yang harus kita lakukan untuk mencapai ini?
Blaze Tama

3
Untuk alat apa jawaban itu? Itu bukan pertanyaan Eclipse.
Michael Piefel

3
Tidak ada "batas minimum". -Xms adalah ukuran awal.
Diego Queiroz

1
Berapa maks batas maksimum yang bisa diatur ??
JPerk

14

Bagi saya, langkah-langkah berikut ini berhasil:

  1. Buka eclipse.ini file
  2. Perubahan

    -Xms40m
    -Xmx512m

    untuk

    -Xms512m
    -Xmx1024m
  3. Mulai ulang Eclipse

Lihat disini


cara paling sederhana untuk memperbaiki masalah ini. Terima kasih :)
Hamza

1
File eclipse.ini di jdev?
Abhinaba Basu

masalah tidak terpecahkan bahkan ketika konfigurasi telah diubah menjadi ini.
zionpi

1
OP tidak mengajukan pertanyaan Eclipse.
Michael Piefel

1
"Jawaban" ini tidak menjawab pertanyaan di atas.
Freitag

13

coba ini

buka build.gradlefile

  android {
        dexOptions {
           javaMaxHeapSize = "4g"
        }
   }

Berfungsi bagus untuk simulator. Adakah yang tahu bagaimana ini memengaruhi perangkat nyata? yaitu apakah ini ide yang bagus atau hanya menutupi masalah? Terima kasih.
Joshua Pinter

11

Berikut ini bekerja untuk saya. Cukup tambahkan cuplikan berikut:

android {
        compileSdkVersion 25
        buildToolsVersion '25.0.1'

defaultConfig {
        applicationId "yourpackage"
        minSdkVersion 10
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }
dexOptions {
        javaMaxHeapSize "4g"
    }
}

Ya, saat menggunakan Gradle :)
Alex

4
Bagaimana Anda bisa berpikir ini adalah solusi untuk pertanyaannya secara umum ? Anda mengatur ukuran tumpukan Anda ke 4g yang benar-benar sewenang-wenang dalam konfigurasi gradle untuk Android facepalm .
Julian L.

7

tingkatkan javaMaxHeapsize di file build.gradle (Module: app) Anda

dexOptions {
    javaMaxHeapSize "1g"
}

ke (Tambahkan baris ini dalam gradle)

 dexOptions {
        javaMaxHeapSize "4g"
    }

3

Deskripsi ukuran tumpukan Java (xms, xmx, xmn)

-Xms size in bytes

Example : java -Xms32m

Mengatur ukuran awal heap Java. Ukuran standar adalah 2097152 (2MB). Nilai harus berupa kelipatan, dan lebih besar dari, 1024 byte (1KB). (Bendera -server meningkatkan ukuran default menjadi 32M.)

-Xmn size in bytes

Example : java -Xmx2m

Mengatur ukuran heap Java awal untuk generasi Eden. Nilai standarnya adalah 640 ribu. (Bendera -server meningkatkan ukuran standar menjadi 2M.)

-Xmx size in bytes

Example : java -Xmx2048m

Mengatur ukuran maksimum tempat tumpukan Java dapat tumbuh. Ukuran standar adalah 64M. (Bendera -server meningkatkan ukuran standar menjadi 128M.) Batas tumpukan maksimum adalah sekitar 2 GB (2048MB).

Argumen memori Java (xms, xmx, xmn) diformat

Saat mengatur ukuran Java heap, Anda harus menentukan argumen memori Anda menggunakan salah satu huruf "m" atau "M" untuk MB, atau "g" atau "G" untuk GB. Pengaturan Anda tidak akan berfungsi jika Anda menentukan "MB" atau "GB." Argumen yang valid terlihat seperti ini:

-Xms64m atau -Xms64M -Xmx1g atau -Xmx1G Bisa juga menggunakan 2048MB untuk menentukan 2GB Juga, pastikan Anda hanya menggunakan bilangan bulat saat menentukan argumen Anda. Menggunakan -Xmx512m adalah opsi yang valid, tetapi -Xmx0.5g akan menyebabkan kesalahan.

Referensi ini dapat bermanfaat bagi seseorang.


2

Anda juga dapat meningkatkan alokasi memori dan ukuran tumpukan dengan menambahkan ini ke gradle.propertiesfile Anda :

org.gradle.jvmargs=-Xmx2048M -XX\:MaxHeapSize\=32g

Tidak harus 2048M dan 32g, buat sebesar yang Anda inginkan.


2

Soal:
Hanya menambahkan
org.gradle.jvmargs=-Xmx1024m
di
gradle.properties
dan jika tidak ada, buatlah.


0

Saya bekerja di Android Studio dan mengalami kesalahan ini ketika mencoba membuat APK yang ditandatangani untuk dirilis. Saya dapat membangun dan menguji APK debug tanpa masalah, tetapi segera setelah saya ingin membangun APK rilis, proses pembangunan akan berjalan selama beberapa menit dan akhirnya diakhiri dengan "Kesalahan java.lang.OutOfMemoryError: GC batas overhead terlampaui ". Saya meningkatkan ukuran heap untuk VM dan Android DEX compiler, tetapi masalahnya tetap ada. Akhirnya, setelah berjam-jam dan cangkir kopi ternyata masalahnya ada di file 'build.gradle' tingkat app saya - saya memiliki parameter 'minifyEnabled' untuk rilis build type yang disetel ke 'false', akibatnya menjalankan barang Proguard pada kode yang belum melalui proses penyusutan kode '(lihat https://developer.android.). Saya mengubah parameter 'minifyEnabled' menjadi 'true' dan rilis rilis dijalankan seperti mimpi :)

Singkatnya, saya harus mengubah file 'build.gradle' tingkat aplikasi saya dari: // ...

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.sign_config_release
    }
    debug {
        debuggable true
        signingConfig signingConfigs.sign_config_debug
    }
}

//...

untuk

    //...

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.sign_config_release
    }
    debug {
        debuggable true
        signingConfig signingConfigs.sign_config_debug
    }
}

//...

0

Untuk menambah ukuran tumpukan di IntelliJ IDEA, ikuti instruksi berikut. Ini berhasil untuk saya.

Untuk Pengguna Windows,

Pergi ke lokasi di mana IDE diinstal dan cari yang berikut.

idea64.exe.vmoptions

Edit file dan tambahkan berikut ini.

-Xms512m
-Xmx2024m
-XX:MaxPermSize=700m
-XX:ReservedCodeCacheSize=480m

Hanya itu saja !!


0

Anda dapat mencoba untuk membuat perubahan pada pengaturan server dengan merujuk pada gambar ini dan meningkatkan ukuran memori untuk memproses perubahan proses yang disorot dengan warna kuning

Anda juga dapat membuat perubahan ke tumpukan java dengan membuka cmd-> set _java_opts -Xmx2g
2g (2gigabytes) tergantung pada kompleksitas program Anda

mencoba menggunakan variabel temp dan variabel kurang konstan

masukkan deskripsi gambar di sini


-1

Anda perlu menambah ukuran memori di Jdeveloper, pergi ke setDomainEnv.cmd .

set WLS_HOME=%WL_HOME%\server    
set XMS_SUN_64BIT=**256**
set XMS_SUN_32BIT=**256**
set XMX_SUN_64BIT=**3072**
set XMX_SUN_32BIT=**3072**
set XMS_JROCKIT_64BIT=**256**
set XMS_JROCKIT_32BIT=**256**
set XMX_JROCKIT_64BIT=**1024**
set XMX_JROCKIT_32BIT=**1024**

if "%JAVA_VENDOR%"=="Sun" (
    set WLS_MEM_ARGS_64BIT=**-Xms256m -Xmx512m**
    set WLS_MEM_ARGS_32BIT=**-Xms256m -Xmx512m**
) else (
    set WLS_MEM_ARGS_64BIT=**-Xms512m -Xmx512m**
    set WLS_MEM_ARGS_32BIT=**-Xms512m -Xmx512m**
)

dan

set MEM_PERM_SIZE_64BIT=-XX:PermSize=**256m**
set MEM_PERM_SIZE_32BIT=-XX:PermSize=**256m**

if "%JAVA_USE_64BIT%"=="true" (
    set MEM_PERM_SIZE=%MEM_PERM_SIZE_64BIT%
) else (
    set MEM_PERM_SIZE=%MEM_PERM_SIZE_32BIT%
)

set MEM_MAX_PERM_SIZE_64BIT=-XX:MaxPermSize=**1024m**
set MEM_MAX_PERM_SIZE_32BIT=-XX:MaxPermSize=**1024m**

4
Pengaturan ini hanya khusus untuk IDE lokal Anda. Ini tidak akan berfungsi untuk lingkungan Prod.
Feng

-1

Di Netbeans, mungkin berguna untuk merancang ukuran tumpukan maksimum. Pergi ke Jalankan => Atur Konfigurasi Proyek => Kustomisasi . Di Jalankan dari jendela yang muncul, buka Opsi VM , isi -Xms2048m -Xmx2048m. Itu bisa memecahkan masalah ukuran tumpukan.


-1

Mem-boot ulang MacBook saya memperbaiki masalah ini untuk saya.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.