управление памятью Java - PullRequest
5 голосов
/ 20 октября 2008

Я программист на С ++ и играю с java после того, как нашел JPA, который для некоторых моих текущих приложений - просто бог. Я не прикасался к Java с университета, и у меня проблемы с нехваткой кучи. Я использую приведенный ниже код в качестве основной части не очень серьезного теста jdbc / jpa / lucene, но продолжаю получать случайные исключения OutOfMemory.

        EntityManager em = emf.createEntityManager();
        Query q = em.createQuery("select p from Product p" +
            " where p.productid = :productid");
        Connection con = DriverManager.getConnection("connection string");
        Statement st = con.createStatement();

        IndexWriter writer = new IndexWriter("c:\\temp\\lucene", new StandardAnalyzer(), IndexWriter.MaxFieldLength.LIMITED);

        ResultSet rs = st.executeQuery("select productid from product order by productid");
        while (rs.next()) {
            int productid = rs.getInt("PRODUCTID");
            q.setParameter("productid", productid);
            Product p = (Product)q.getSingleResult();

            writer.addDocument(createDocument(p));
        }

        writer.commit();
        writer.optimize();
        writer.close();

        st.close();
        con.close();

Я не буду публиковать все createDocument, но все, что он делает - это создает новый org.apache.lucene.document.Document и добавляет поля с помощью add (new Field ...) и т. Д. Всего около 50 полей и большинство из них короткие (менее 32 символов).

В моем новоселье есть что-то совершенно глупое, что я делаю (или нет), которое заставило бы вещи не быть GC'd?

Существуют ли лучшие практики в отношении управления памятью Java и работы с GC?

Ответы [ 6 ]

3 голосов
/ 20 октября 2008

Я не вижу ничего явно неуместного. Если вы работаете с очень большой базой данных, вы можете попробовать увеличить размер кучи, используя опцию -Xmx n в вашем вызове JVM. Это обычно не лучшее решение - делайте это только тогда, когда вы знаете, что ваш рабочий набор на самом деле больше размера кучи по умолчанию.

Используете ли вы какие-либо сложные структуры данных? Если у вас есть циклические ссылки между объектами, вы можете помешать сборщику мусора очистить недоступные объекты. Если у вас есть какие-либо рукописные структуры данных, убедитесь, что вы явно обнулили ссылки на объекты, которые были удалены, вместо того чтобы делать что-то вроде уменьшения переменной размера.

2 голосов
/ 22 октября 2008

Возможно, вам не хватает места для постоянного поколения. Проверьте, содержит ли ваша трассировка стека что-то вроде java.lang.OutOfMemoryError: PermGen

Вы можете увеличить пространство для этого поколения с помощью этого параметра для jvm: -XX: MaxPermSize = 128m

Объекты постоянной генерации не учитываются при сборке мусора. Взгляните на эту страницу от sun , чтобы узнать больше о сборке мусора и различных поколениях объектов в JVM.

2 голосов
/ 20 октября 2008

Ну ...

Многолетний опыт работы с Java и базами данных ( пример post различия в Oracle PostgresSQL MySQL>) научил меня, что драйверы JDBC, которые мы используем при выполнении этой работы, часто имеют проблемы.

У меня есть один фрагмент кода, который должен оставаться подключенным к базе данных 24/7, и из-за утечки памяти драйвера JVM всегда будет задыхаться в какой-то момент. Итак, я написал код, чтобы перехватить конкретное выброшенное исключение, а затем предпринять все более радикальные действия, в том числе разорвать соединение, переподключить и даже перезапустить JVM в отчаянном состоянии, ничего не помогло, чтобы устранить проблему. Какая боль, чтобы написать это, но она работала, пока поставщик СУБД не выпустил новый драйвер JDBC, который не вызывал проблемы ... На самом деле я просто оставил код на месте, на всякий случай!

... Значит, вы ничего не делаете.

Обратите внимание, что вызов сборщика мусора был одной из стратегий, которые я использовал, но метрики показали, что это редко помогает.

Кроме того, это может быть не совсем понятно, но ResultSets поддерживает постоянное соединение с самим механизмом базы данных, во многих случаях (если явно не указано иное), двунаправленным, даже если вы просто читаете. И некоторые драйверы JDBC позволяют запрашивать однонаправленное соединение, но лгать и возвращать двунаправленное соединение! Осторожно с этим!

Таким образом, рекомендуется выгрузить объекты ResultSet в другие объекты для хранения значений и как можно скорее удалить сами объекты ResultSet.

Удачи. RTIII

2 голосов
/ 20 октября 2008

Попробуйте анализатор памяти SAP.

https://www.sdn.sap.com/irj/sdn/wiki?path=/display/Java/Java+Memory+Analysis

Это читает файл дампа и позволяет вам исследовать, что занимает память.

0 голосов
/ 22 октября 2008

Java поддерживает несколько различных пулов памяти, и из-за нехватки любого из них может возникнуть страшное исключение OutOfMermoryException. Проблемы с выделением памяти операционной системой также могут проявляться как OOM.

Вы должны увидеть подробную трассировку стека - или, возможно, файл дампа ошибок в каталоге приложения - который может дать дополнительные подсказки о проблеме.

Если вы используете приличный профилировщик - JVisualVM, который поставляется с последними JDK Sun Java 6, вероятно, достаточно - вы можете просмотреть все различные пулы и посмотреть, какие из них заканчиваются.

0 голосов
/ 20 октября 2008

Сколько предметов в вашем наборе результатов? Если записей достаточно, то вы израсходуете всю свою память, поскольку в этом случае сборщик мусора не будет собираться, когда вы делаете addDocument для модуля записи, который будет содержать ссылку на все создаваемые вами документы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...