为什么即使在 driverThreadLocal.remove() 之后,webdriver 在使用多线程时也会导致 java spring boot 应用程序内存泄漏?

问题描述 投票:0回答:1

Webdriver 导致我的 Spring Boot 应用程序出现内存泄漏。即使驱动程序退出后,内存也没有完全释放,导致内存泄漏。

我正在运行 2 个独立的线程,每个线程每次被请求时都会遵循一些步骤:

  1. 启动驱动程序;
  2. 导航到网页,在本例中为 google.com;
  3. 关闭驱动;

这是我写的代码:

主课:

@SpringBootApplication
@ServletComponentScan
public class App {
    
    public static void main(String[] args) throws IOException {
        ApplicationContext context = SpringApplication.run(App.class, args);    
        
        //REQUESTING THE ENDPOINT THROUGH CODE
        RestTemplate restTemplate = context.getBean(RestTemplate.class);
        restTemplate.getForEntity("http://localhost:8080/hello", Void.class);
    }
}

配置类:

@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean(name="asyncTaskExecutor")
    public Executor asyncTaskExecutor(){
        System.out.println("CONFIGURING ASYNC TASKS");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
        executor.setCorePoolSize(2); 
        executor.setMaxPoolSize(2); 
        executor.setQueueCapacity(100); 
        executor.setThreadNamePrefix("Async Thread-"); 
        executor.initialize();
        return executor; 
    }
    
    
    // Configuração do RestTemplate
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}

服务等级:

@Service
public class MyService{
    
    
    private static ThreadLocal<WebDriver> driverThreadLocal = ThreadLocal.withInitial(() -> null);
    public static WebDriver getDriver() {
        return driverThreadLocal.get();
    }
    
    public static void setDriver(WebDriver driver) {
        driverThreadLocal.set(driver);
    }
    
    public static void quitDriver() {
        getDriver().quit();
        driverThreadLocal.remove();
    }   
    
    @Async("asyncTaskExecutor")
        public void scrappingtask() throws IOException {
            System.out.println("REQUEST STARTS");
            System.out.println("Thread group: "+Thread.currentThread().getThreadGroup());
            System.out.println("Thread name: " + Thread.currentThread().getName());
            System.out.println("Thread id: " + Thread.currentThread().getId());
        
        
        if (getDriver() == null) {
            System.out.println("*******WEBDRIVER START FOR THE THREAD "+ Thread.currentThread().getName()); 
            System.setProperty("webdriver.chrome.driver","YOUR_CHROME_DRIVER_EXE_PATH"); 
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--headless");
            options.addArguments("--disable-cache");
            driverThreadLocal.set(new ChromeDriver(options));
        } 
        
        System.out.println("WEBDRIVER'S SESSION_ID FOR THE THREAD "+ Thread.currentThread().getName()+":"+((ChromeDriver)driverThreadLocal.get()).getSessionId());

        getDriver().get("https://google.com");
        
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        
        System.out.println("REQUEST ENDS");
        quitDriver(); 
    }
}

测试用例:

@Controller
public class TestCases {

    @Autowired
    private MyService myservice;
    
    @GetMapping("/hello")
        public synchronized void runtestcases() throws IOException {
            int i;
            for (i = 1; i <= 10; i++) {
                try {
                    Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println(i);
            try {
                myservice.scrappingtask();
            } catch (Exception e) {
            // TODO Auto-generated catch block          
            e.printStackTrace();
            }
        }       
    }
}

我期望堆内存始终处于进程开始时的同一水平,但它不断增加,如下图所示:

VisualVM 监控画面

堆转储

spring-boot multithreading selenium-webdriver memory-leaks
1个回答
0
投票

之前运行代码时,HEAP MEMORY SIZE 没有限制,因此系统没有对内存进行优化。

新的池块正在被分配,并且由于内存足以扩展堆大小,系统不会被迫清理它们。

有关 poolchunk 过程的更多信息可在此处获得。

从我的配置中删除行

executor.setMaxPoolSize(2);
并在 Eclipse 的运行配置上设置最大堆内存后,问题得到解决。

Eclipse IDE 上最大堆内存的配置

我们可以看到,在这些更改之后运行相同的代码时,堆数据使用量减少了:

更改后的VisualVM监控画面

从线程转储中,我们可以注意到池块不再累积。

© www.soinside.com 2019 - 2024. All rights reserved.