首页 文章

Java 8完整GC和OutOfMemory Java堆空间

提问于
浏览
4

使用 VisualVM 并检查 Tomcat 8.5 catalina.out日志我每次都看到 almost (11次中有7次左右)当 full GC 发生日志时显示 OutOfMemory (在同一分钟) .

Tomcat parameters 与内存管理有关: -Xms3G -Xmx=6G -XX:+UseG1GC -XX:+UseStringDeduplication -XX:MaxHeapFreeRatio=100

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

虽然这是 memory usage graphdifferent 设置为 JVM parameters (无法获得具有旧JVM参数的ATM),但在完全GC内存使用 grows rapidly 之后,它的方式类似,相同的最大值 . 堆大小和最大堆大小不会下降 .

enter image description here

Any ideas why this could happen?

Update: 我忘了提到以前 full GCOutOfMemory 会在堆大小 was not even full - 〜5GB时发生 . 当时没有一次我看到堆达到6GB .

3 回答

  • 0

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

  • 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));
    
  • 1

    如果为大多数参数设置默认值,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正在成长 . 检查可能的内存泄漏 . 如果没有发现内存泄漏,请进一步增加堆内存 .

相关问题