Управление памятью Java

Я программист на C++, и я играю с 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?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
0
1 021
6

Ответы 6

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

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

У GC нет проблем с циклическими ссылками, объекты все равно будут удалены. Я не уверен, что понимаю, что вы подразумеваете под явным обнулением ссылок на объекты. Как еще бы вы их удалили?

Robin 20.10.2008 05:31

Другой способ избавиться от них - выпустить их из поля зрения. Явная установка ссылок на null предназначена для комбинации огромных объектов и длинных циклов, когда ссылка на объект будет храниться в памяти в течение длительного времени.

gnud 20.10.2008 05:35

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

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

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

Ваша ссылка меня не ведет. Исправьте пожалуйста ссылку!

Richard T 20.10.2008 06:02

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

Что ж...

Многолетний опыт работы с Java и базами данных (пример сообщенияpostgresSQL mysql oracle sizes>) научил меня, что драйверы JDBC, которые мы используем при выполнении этой работы, часто имеют проблемы.

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

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

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

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

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

Удачи. RTIII

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

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

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

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

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

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

Другие вопросы по теме