Spring Boot 项目中的 GC Root

可达性分析是一种用于判定对象是否可以被垃圾回收的算法。基本思想是通过一个称为"根集合"(GC Root)的起点集合,来追踪对象引用。如果一个对象从根集合开始可以被追踪到,那么它就是"可达"的,否则就是"不可达"的,可以被认为是垃圾,因而可以被回收。

GC Root是可达性分析的起点。在Java中,以下几种类型的对象可以作为GC Root:

  1. Java栈中的引用对象:即当前正在被调用的方法中的局部变量和输入参数。
  2. 静态属性引用的对象:即所有类的静态属性(静态变量)。
  3. 常量引用的对象:即常量池中的引用(如字符串常量)。
  4. 本地方法栈中的引用对象:即本地方法(Native方法)中引用的对象。
  5. 活动线程:所有正在运行的线程。

纯粹的Spring Boot

Spring Boot构建的软件项目中,GC Root的概念与在任何其他Java应用程序中相同,但由于Spring Boot的结构和特性,有一些特定的地方可能成为GC Root。以下是Spring Boot项目中特别需要注意的几个GC Root来源:

  1. 应用程序上下文 (Application Context)

    Spring Boot应用程序上下文持有许多Bean的引用。这些Bean通常包括服务、控制器、配置等。由于应用程序上下文是通过静态方法访问的,它们往往会作为GC Root。

  2. 静态变量

    任何静态变量都可能作为GC Root。例如,在Spring Bean中声明的静态字段或通过静态方法访问的资源。

  3. 线程池

    Spring Boot应用程序通常使用线程池来处理并发请求。线程池中的线程会引用许多对象,这些线程会作为GC Root,防止这些对象被回收。

  4. Servlet容器中的对象

    Spring Boot通常嵌入一个Servlet容器(如Tomcat、Jetty)。这些容器中的对象(如HttpSession、ServletContext等)也可能成为GC Root。

  5. JVM本地方法栈

    任何在Spring Boot应用程序中使用的JNI(Java Native Interface)调用所引用的对象,也会作为GC Root。

java 复制代码
@SpringBootApplication
public class SpringBootGCRootDemoApplication {

    // 静态变量,GC Root
    private static MyService myStaticService;

    @Autowired
    private MyService myService;

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringBootGCRootDemoApplication.class, args);

        // 应用程序上下文中的Bean,GC Root
        myStaticService = context.getBean(MyService.class);
    }

    @RestController
    @RequestMapping("/api")
    public static class MyController {

        // 控制器中的依赖,GC Root
        @Autowired
        private MyService myService;

        @GetMapping("/hello")
        public String sayHello() {
            return myService.getMessage();
        }
    }

    @Service
    public static class MyService {

        public String getMessage() {
            return "Hello, World!";
        }
    }
}

在Spring Boot构建的软件项目中,结合Spring、Spring MVC、MyBatis等框架来实现三层模型(MVC模式),以下是这些框架中的一些关键组件以及它们如何成为GC Root的解释:

三层模型(MVC模式)

通常的三层架构分为:

  1. 表示层(Presentation Layer):处理用户的请求和响应。
  2. 业务逻辑层(Business Logic Layer):处理具体的业务逻辑。
  3. 数据访问层(Data Access Layer):处理数据库访问。

以下是Spring Boot项目中使用Spring、Spring MVC、MyBatis等框架时,哪些组件会成为GC Root:

表示层(Presentation Layer)

  1. Spring MVC 控制器 (Controllers)

    • 控制器类和它们的实例通常是单例(Singleton),并且由Spring容器管理。
    • 这些实例通过Spring上下文持有,会成为GC Root。
    java 复制代码
    @RestController
    @RequestMapping("/api")
    public class MyController {
        @Autowired
        private MyService myService;
        
        @GetMapping("/hello")
        public String sayHello() {
            return myService.getMessage();
        }
    }
  2. Servlet 容器中的对象

    • Spring Boot内嵌的Servlet容器(如Tomcat、Jetty)会维护一些长生命周期的对象,如HttpSessionServletContext,这些也会成为GC Root。

业务逻辑层(Business Logic Layer)

  1. Spring Service 层的Bean

    • Service类通常也是单例,并且由Spring容器管理。
    • 这些Bean通过Spring上下文持有,会成为GC Root。
    java 复制代码
    @Service
    public class MyService {
        public String getMessage() {
            return "Hello, World!";
        }
    }

数据访问层(Data Access Layer)

  1. MyBatis Mapper

    • MyBatis Mapper接口的实现由MyBatis框架生成,并通过Spring容器管理。
    • 这些Mapper对象被Service层引用,而Service层又被控制器引用,间接地,这些Mapper对象会成为GC Root的一部分。
    java 复制代码
    @Mapper
    public interface MyMapper {
        @Select("SELECT * FROM my_table WHERE id = #{id}")
        MyEntity getById(int id);
    }
  2. 数据库连接和会话

    • 数据库连接池中的连接对象(如HikariCP、C3P0)和MyBatis的SqlSession对象,由于其生命周期管理,这些对象也会成为GC Root。

示例代码总结

以下是一个综合示例,展示Spring Boot项目中如何使用这些组件:

java 复制代码
@SpringBootApplication
public class SpringBootGCRootDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootGCRootDemoApplication.class, args);
    }

    @RestController
    @RequestMapping("/api")
    public static class MyController {
        @Autowired
        private MyService myService;

        @GetMapping("/hello")
        public String sayHello() {
            return myService.getMessage();
        }
    }

    @Service
    public static class MyService {
        @Autowired
        private MyMapper myMapper;

        public String getMessage() {
            MyEntity entity = myMapper.getById(1);
            return "Hello, " + entity.getName();
        }
    }

    @Mapper
    public interface MyMapper {
        @Select("SELECT * FROM my_table WHERE id = #{id}")
        MyEntity getById(int id);
    }

    public static class MyEntity {
        private int id;
        private String name;
        // getters and setters
    }
}

总结

在Spring Boot应用中,以下组件通常会作为GC Root:

  • Spring上下文管理的控制器、服务和Mapper
  • Servlet容器中的长生命周期对象
  • 数据库连接池中的连接对象
  • 活动线程

这些组件和对象由于它们在应用程序中的关键角色,会被GC Root引用,从而不会被垃圾回收。理解这些GC Root的来源,对于调试和优化Spring Boot应用程序的内存使用非常重要。

相关推荐
爬山算法23 分钟前
Maven(28)如何使用Maven进行依赖解析?
java·maven
hlsd#30 分钟前
go mod 依赖管理
开发语言·后端·golang
陈大爷(有低保)34 分钟前
三层架构和MVC以及它们的融合
后端·mvc
亦世凡华、35 分钟前
【启程Golang之旅】从零开始构建可扩展的微服务架构
开发语言·经验分享·后端·golang
河西石头35 分钟前
一步一步从asp.net core mvc中访问asp.net core WebApi
后端·asp.net·mvc·.net core访问api·httpclient的使用
2401_857439691 小时前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧6661 小时前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
李老头探索1 小时前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
芒果披萨1 小时前
Filter和Listener
java·filter
qq_4924484461 小时前
Java实现App自动化(Appium Demo)
java