Saya menjalankan aplikasi Spring Boot di Wildfly 18.0.1. Tujuan utama dari aplikasi ini adalah: setiap 5 menit menjalankan beberapa pekerjaan. Jadi saya membuat:
Penjadwal Tugas: menginisialisasi penjadwal
@Autowired
ThreadPoolTaskScheduler taskScheduler;
taskScheduler.scheduleWithFixedDelay(new ScheduledVehicleDataUpdate(), 300000);
ScheduledVehicleDataUpdate: penjadwal yang menjalankan pembaru
public class ScheduledVehicleDataUpdate implements Runnable {
@Autowired
TaskExecutor taskExecutor;
@Override
public void run() {
try {
CountDownLatch countDownLatch;
List<VehicleEntity> vehicleList = VehicleService.getInstance().getList();
if (vehicleList.size() > 0) {
countDownLatch = new CountDownLatch(vehiclesList.size());
vehicleList.forEach(vehicle -> taskExecutor.execute(new VehicleDataUpdater(vehicle, countDownLatch)));
countDownLatch.await();
}
}
catch (InterruptedException | RuntimeException e) {
System.out.println(e.getMessage())
}
}
}
Pelaksana Tugas:
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(23);
executor.setMaxPoolSize(23);
executor.setQueueCapacity(5000);
executor.setThreadNamePrefix("VehicleService_updater_thread");
executor.initialize();
return executor;
}
VehicleDataUpdater: kelas pembaru utama
public class VehicleDataUpdater implements Runnable {
private final VehicleEntity vehicle;
private final CountDownLatch countDownLatch;
public VehicleDataUpdater(VehicleEntity vehicle, CountDownLatch countDownLatch) {
this.vehicle = vehicle;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
this.updateVehicleData();
}
catch (Exception e) {
System.out.println(e.getMessage());
}
finally {
countDownLatch.countDown();
}
}
public void updateVehicleData() {
// DO UPDATE ACTIONS;
}
}
Masalahnya adalah setelah ScheduledVehicleDataUpdate selesai, memori TIDAK terhapus. Tampilannya seperti ini:
Setiap langkah memori tumbuh, berkembang, berkembang dan pada saat yang tidak terduga semua memori dilepaskan. Dan objek dari iterasi pertama, dan objek dari iterasi terakhir. Dalam kasus yang paling buruk, dibutuhkan semua memori yang tersedia (120Gb) dan Wildfly mogok.
Saya memiliki sekitar 3200 catatan VehicleEntity (anggap saja 3200). Jadi saya mencari VehicleDataUpdater - berapa banyak objek yang ada di memori. Setelah iterasi pertama (saat saya baru memulai aplikasi) nilainya kurang dari 3200 tetapi tidak nol - mungkin sekitar 3000-3100. Dan setiap langkahnya bertambah tetapi tidak persis pada 3200 catatan. Artinya, beberapa objek terhapus dari memori namun sebagian besar tetap berada di sana.
Berikutnya: durasi iterasi normal adalah sekitar 30 detik - 1 menit. Ketika memori tidak jernih dan terus bertambah maka setiap iterasi mendapatkan lebih banyak waktu: waktu terlama yang saya lihat adalah 30 menit. Dan thread dari pool sebagian besar berada dalam status "monitor", yaitu ada beberapa kunci yang menunggu untuk dilepaskan. Mungkin mengunci dari iterasi sebelumnya yang tidak dirilis - dan bertanya lagi - mengapa semua memori tidak dikosongkan pada langkah sebelumnya?
Jika saya menjalankan pembaruan dalam satu utas (tanpa taskExecutor, cukup vehicleList.foreach(vehicle -> VehicleDataUpdater(vehicle)); ) maka saya tidak melihat memori bertambah. Setelah pembaruan, setiap memori kendaraan dihapus.
Saya tidak menemukan masalah kebocoran memori untuk ThreadPoolTaskExecutor atau ThreadPoolTaskScheduler, jadi saya tidak tahu cara memperbaikinya.
Apa cara yang mungkin untuk tidak mengosongkan memori setelah menyelesaikan tugas penjadwal? Bagaimana saya bisa melihat siapa yang mengunci objek setelah selesai? Saya menggunakan VisualVM 2.0.1 dan tidak menemukan kemungkinan seperti itu.
EDIT 1:
Layanan Kendaraan:
public class VehicleService {
private static VehicleService instance = null;
private VehicleDao dao;
public static VehicleService getInstance(){
if (instance == null) {
instance = new VehicleService();
}
return instance;
}
private VehicleService(){}
public void setDao(VehicleDao vehicleDao) { this.dao = vehicleDao; }
public List<VehicleEntity> list() {
return new ArrayList<>(this.dao.list(LocalDateTime.now()));
}
}
Dao Kendaraan:
@Repository
public class VehicleDao {
@PersistenceContext(unitName = "entityManager")
private EntityManager entityManager;
@Transactional("transactionManager")
public List<VehicleRegisterEntity> list(LocalDateTime dtPeriod) {
return this.entityManager.createQuery("SOME_QUERY", VehicleEntity.class).getResultList();
}
}
Layanan Init:
@Service
public class InitHibernateService {
private final VehicleDao vehicleDao;
@Autowired
public InitHibernateService(VehicleDao vehicleDao){
this.vehicleDao = vehicleDao;
}
@PostConstruct
private void setDao() {
VehicleService.getInstance().setDao(this.vehicleDao);
}
}
Manajer Entitas:
@Bean(name = "entityManager")
@DependsOn("dataSource")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceProviderClass(HibernatePersistenceProvider.class);
em.setDataSource(dataSource());
em.setPackagesToScan("MY_PACKAGE");
em.setJpaVendorAdapter(vendorAdapter());
em.setJpaProperties(hibernateProperties());
em.setPersistenceUnitName("customEntityManager");
em.setJpaDialect(new CustomHibernateJpaDialect());
return em;
}
VehicleService.getInstance().getList()
? Anda juga mungkin harus memperbarui/membaca sesuatu dalam potongan/malas, bukan daftar. Dengan asumsi Anda menggunakan sesuatu seperti JPA, Anda mungkin memiliki masalah lain dengan entitas yang terpisah. Secara keseluruhan, tidak ada cukup informasi dalam pertanyaan Anda untuk menjawabnya. - person M. Deinum   schedule 23.04.2020ScheduledVehicleDataUpdate
Anda harus berupa kacang yang dikelola pegas dengan@Scheduled
sehingga Spring memasukkan dependensi dan menggunakan@Scheduled
untuk menjadwalkan berbagai hal. Anda harus bekerja DENGAN kerangka kerja yang sedang Anda kerjakan. Mengenai potongannya, itu mungkin tidak sepenuhnya berfungsi dengan solusi Anda saat ini. Apakah Anda juga memerlukan semua tugas kecil itu? Mengapa tidak melakukan pembaruan secara berurutan saja? - person M. Deinum   schedule 23.04.2020@Scheduled
dan membaca dari file properti, jadi tidak ada yang menghalangi Anda melakukan desain yang benar. - person M. Deinum   schedule 23.04.2020