Comments 20
Самое главное-то и не рассказали: был ли этот код потом убран — или так и остался на продашкене? :)
Hibernate = зло
Но как узнать, где порождается такое большое количество объектов? Искать по коду? Не вариант, придется делать поиск по всей системе, а времени в обрез – заказчик уже весь синеет.
Я конечно извиняюсь, но вроде бы, поднятие общих бизнес сущностей выносят в отдельные классы, тогда и связность системы понизилась бы, поиск с модификацией кода работающего с entity стали куда проще, да и необходимость у программистов сто первый раз писать велосипед, вроде того поднятия entity не было бы. Плюс часто делают свои обертки над классами JPA'а, вроде entityManager'a, чтобы, например, было проще отлаживать и профилировать поднятие entity (на самом деле, так ещё куча других полезных вещей). Тогда не нужно было делать всех этих хаков с конструктором.
Хорошо, допустим, сущность «поднимается» всего в одном методе, а метод вызывается в 100500 местах. Что-то изменилось от замены конструктора на метод? Стало ли проще найти то место, где этот метод вызывается чаще всего?
Ну, смотрите делаем, например, грубо говоря такой сервис
Теперь нам не нужно искать вообще все Payment'ы, достаточно сделать поиск по getAllPayment и getPaymentByQuery и понять где программисты промахнулись. Крайне редко проблема будут в цикле с getPaymentById.
public interface ServicePayment {
Payment getPaymentById(String id);
Payment getAllPayment();
Payment getPaymentByQuery(String query);
}
Теперь нам не нужно искать вообще все Payment'ы, достаточно сделать поиск по getAllPayment и getPaymentByQuery и понять где программисты промахнулись. Крайне редко проблема будут в цикле с getPaymentById.
Ну вот нашли вы 100400 мест, где используются getAllPayment или getPaymentByQuery. Что дальше?
Если бы нашел 100400 мест, где используются getAllPayment, прибил бы архитектора. Шутка. Вызовы getAllPayment на 2 млн. entity, скорее всего могут должны использоваться только для задач интеграции, обслуживание БД и т.п. Если такой метод используется в обычных модулях это уже повод понять зачем.
Если есть куча мест где используется getPaymentByQuery(«name = ?»), то это повод выделить его в отдельный метод getPaymentByName, создать индекс по полю name, сделать тест производительности метода на реальной базе и т.д. Также для всех подобных методах, в результате большинство частых запросов можно будет выделить в отдельные методы. А дальше всегда можно использовать профайл и т.п. методики на отдельных методах. Метод getPaymentByQuery имеет смысл именно для действительно уникальных случаев и опять-таки ловится профайлером, логированием времени работы и т.п. методами
Ну, например что будет узнаете ли вы когда нибудь, что у вас используется в 100400 мест запросы вида «Payment.name = ?», но индекс по поля name вы сделать забыли, отчего вся ваша система дико тормозит? Ни один профайлер не сможет собрать такие запросы из 100400 мест, насколько я знаю.
Если есть куча мест где используется getPaymentByQuery(«name = ?»), то это повод выделить его в отдельный метод getPaymentByName, создать индекс по полю name, сделать тест производительности метода на реальной базе и т.д. Также для всех подобных методах, в результате большинство частых запросов можно будет выделить в отдельные методы. А дальше всегда можно использовать профайл и т.п. методики на отдельных методах. Метод getPaymentByQuery имеет смысл именно для действительно уникальных случаев и опять-таки ловится профайлером, логированием времени работы и т.п. методами
Ну, например что будет узнаете ли вы когда нибудь, что у вас используется в 100400 мест запросы вида «Payment.name = ?», но индекс по поля name вы сделать забыли, отчего вся ваша система дико тормозит? Ни один профайлер не сможет собрать такие запросы из 100400 мест, насколько я знаю.
Но вы понимаете, что в сумме по всем методам число мест, откуда они вызываются, будет постоянным, как их не переименовывай?
PS убийство архитектора в отсутствии машины времени проблему не решает.
PS убийство архитектора в отсутствии машины времени проблему не решает.
А профайлер бы не показал наиболее часто вызываемые и «долгоиграющие» методы?
Можно было бы похожее сделать с помощью AspectJ и не писать в лог, а писать в set сам StackTraceElement и сделать каунтер. Плюсы — без модификации кода и можно поймать точку вызова конструктора
Это если AspectJ у вас под рукой и есть тот, кто знает как им пользоваться… Можно при желании и свой профилировщик написать…
Так и делает мой коллега.
Он есть всегда и со всеми зависимостями
org.aspectjaspectjrt1.8.4
И научиться пользоваться им гораздо проще чем разгребать гигабайты логов!
Это если AspectJ у вас под рукой
Он есть всегда и со всеми зависимостями
org.aspectjaspectjrt1.8.4
И научиться пользоваться им гораздо проще чем разгребать гигабайты логов!
А можно было бы просто подключить github.com/devexperts/aprof
Такая же ситуация была, с аналогичным скриптом. Тоже горе хапнули
А почему не использовали Flight Recorder из Java Mission Control ?
Без видимых снижений производительности (всего около 2%) можно на боевом окружении увидеть проблемы с памятью:
— Allocation By Class — как раз то что вы написали
— Allocation By Thread
Без видимых снижений производительности (всего около 2%) можно на боевом окружении увидеть проблемы с памятью:
— Allocation By Class — как раз то что вы написали
— Allocation By Thread
Sign up to leave a comment.
Рассказ о том, как я с помощью логов нашел «пожирателя» памяти