2017-09-07 38 views
4

使用VisualVM的和检查的Tomcat 8.5 catalina.out的日志我看到几乎每次(7的11倍左右)时完整的GC发生日志显示OutOfMemory(在完全相同的分钟)。Java的8个全GC和内存溢出的Java堆空间

对于Tomcat 参数有事可做内存管理:-Xms3G -Xmx = 6G -XX:+ UseG1GC -XX:+ UseStringDeduplication -XX:MaxHeapFreeRatio = 100

在第一我认为这是因为默认-XX:MaxHeapFreeRatio值是,因为我看到了最大值。堆大小(当然使用的堆)将在全满GC - 至〜10-20%期间显着下降。但是,添加XX:MaxHeapFreeRatio = 100没有解决它。

虽然这是内存使用图形不同JVM的参数(不能得到一个与旧JVM参数ATM)是经过充分的GC存储的方式类似用法快速增长,最大值相同堆大小和最大值。堆大小不会下降。

enter image description here

任何想法,为什么这可能发生?

更新:我忘了提,以前完整的GC内存不足会发生当堆大小甚至不是全 - 〜5GB。当时没有一次我看到堆达到6GB。

+0

您应该调整这些JVM GC参数:http://blog.sokolenko.me/2014/11/javavm-options-production.html – duffymo

+0

在提出类似问题之前,请执行一些分析,例如,您可以使用YourKit。 在你的情况下,它可能发生,因为GC无法跟上太多的对象被创建和释放在短时间内。 – tsolakp

回答

1

很明显,一些创建的对象不能被正确地垃圾收集。您可以尝试使用VisualVM的采样器功能并跟踪创建的实例数量。

+0

你是对的,这就是OOM的意思,但是当剩下大约1GB可用空间时(参见问题更新),以及在发生完全GC时,OOM如何发生。 – user435421

+0

这可能有几个原因。如果permgen空间已满,或者没有可用的连续内存块来创建大型数组或对象,或者如果GC花费的时间太长,则数组大小超过允许的jvm限制等。 – Alex

0

尝试使用MapDB缓存IO操作。

你可以像这样把它缓存到一个基于磁盘的文件数据库:

import java.io.File; 
import java.io.IOException; 
import java.util.Map; 
import org.mapdb.DB; 
import org.mapdb.DBMaker; 

/** 
* Singleton class. 
*/ 
public class DBManager 
{ 
     /** 
    * Variables. 
    */ 
    private static File dbFile = new File("path/to/file"); 
    private DB db; 
    private static final String password = "yourPassword"; 
    private Map<Integer, String> ctDB; 
    private static DBManager manager; 

    /** 
    * Singleton operations. 
    */ 

    /** 
    * Static initializer. 
    */ 
    static 
    { 
    manager = null; 
    } 

/** 
* Singleton method @see DBManager.getInstance(File dbFile); 
* @return   -> An object/instance of this class. 
*/ 
public static DBManager getInstance() 
{  
    if(isFileDatabaseOK()) 
    { 
     /** 
     * Check if an object/instance from this class exists already. 
     */ 
     if(manager == null) 
     { 
      manager = new DBManager(); 
     } 

     /** 
     * Return an object/instance of this class. 
     */ 
     return manager; 
    } 
    else 
    { 
     return null; 
    } 
} 

/** 
* Constructors. 
*/ 

/** 
* Empty default Constructor starts the MapDB instance. 
*/ 
private DBManager() 
{  
    /** 
    * Load the database file from the given path 
    * and initialize the database. 
    */ 
    initMapDB(); 
} 

/** 
* MapDB initializer. 
*/ 

/** 
* Initialize a MapDB database. 
*/ 
private void initMapDB() 
{ 
    /** 
    * Persistence: Make MapDB able to load the same database from the 
    * file after JVM-Shutdown. Initialize database without @see  org.mapdb.DBMaker.deleteFilesAfterClose() 
    * @see <link>https://groups.google.com/forum/#!topic/mapdb/AW8Ax49TLUc</link> 
    */ 
    db = DBMaker.newFileDB(dbFile) 
      .closeOnJvmShutdown()  
      .asyncWriteDisable() 
      .encryptionEnable(password.getBytes()) 
      .make(); 

    /** 
    * Create a Map/Get the existing map. 
    */ 
    ctDB = db.getTreeMap("database"); 
} 

/** 
* File existence check. 
* If file doesn't exists -> Create a new db file and inform the user. 
*/ 
private static boolean isFileDatabaseOK() 
{  
    /** 
    * If the file doesn't exists (First run) create a new file and 
    * inform the user. 
    */ 
    if(!dbFile.exists()) 
    { 
     try 
     { 
      dbFile.getParentFile().mkdirs(); 
      dbFile.createNewFile(); 

      /** 
      * TODO 
      * System.out.println("Database not found. Creating a new one."); 
      */ 

      return true; 
     } 
     catch (IOException e) 
     { 
      /** 
      * TODO Error handling 
      */ 
      e.printStackTrace(); 
      return false; 
     } 
    } 
    else 
    {   
     return true; 
    } 
} 

/** 
* Database methods/operations. 
*/ 

/** 
* Get objects by id. 
* @param id -> Search parameter. 
* @return  -> The object that belongs to the id. 
*/ 
public String get(int id) 
{ 
    return ctDB.get(id); 
} 

/** 
* Adding objects to the database. 
* @param id -> The key reference to the object as 'id'. 
* @param object -> The object to cache. 
*/ 
public void put(int id, String object) 
{ 
    ctDB.put(id, object); 

    db.commit(); 
} 
} 

然后执行:

DBManager manager = DBManager.getInstance(); 
manager.put(1, "test"); 
Sytem.out.println(manger.get(1)); 
0

G1GC效果很好,如果你大部分的设置默认值参数。只设置关键参数

-XX:MaxGCPauseMillis 
-XX:G1HeapRegionSize 
-XX:ParallelGCThreads 
-XX:ConcGCThreads 

并将所有其他内容留给Java。

您可以在文章下方找到更多的细节:

Java 7 (JDK 7) garbage collection and documentation on G1

Why do I get OutOfMemory when 20% of the heap is still free?

使用像mat一些内存分析工具了解根本原因。

就你而言,显然oldgen正在增长。检查可能的内存泄漏。如果您没有发现内存泄漏,请进一步增加堆内存。