Java 8完整GC和OutOfMemory Java堆空间

时间:2017-09-07 14:16:54

标签: java tomcat garbage-collection out-of-memory

使用 VisualVM 并检查 Tomcat 8.5 catalina.out日志我每次都看到 几乎 (7次出11次左右)当 完整的GC 发生时,日志显示 OutOfMemory (在同一分钟)。< / p>

使用与内存管理有关的Tomcat 参数 -Xms3G -Xmx = 6G -XX:+ UseG1GC -XX:+ UseStringDeduplication -XX :MaxHeapFreeRatio = 100

起初我认为这是因为默认 -XX:MaxHeapFreeRatio 70 ,因为我看到了最大值。在 完整GC - ~10-20%期间,堆大小(当然使用的堆)会显着下降。但是,添加 XX:MaxHeapFreeRatio = 100 并没有解决问题。

虽然这是 内存使用情况 ,但 不同 JVM参数< / em> (无法获得具有旧JVM参数的ATM)在完全GC内存使用 快速增长 后,它在某种程度上相似,同样最大。堆大小和最大堆大小不会下降。

enter image description here

为什么会发生这种情况的任何想法?

更新:我忘了提及之前 完整的GC OutOfMemory 堆大小 甚至不满 时会发生 - 〜5GB。当时我没看到堆达到6GB。

3 个答案:

答案 0 :(得分:1)

显然,创建的某些对象无法正确收集垃圾。您可以尝试使用VisualVM的采样器功能并跟踪创建的实例数。

答案 1 :(得分: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));

答案 2 :(得分: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正在成长。检查可能的内存泄漏。如果没有发现内存泄漏,请进一步增加堆内存。