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应用程序的内存使用非常重要。

相关推荐
东风破_5 小时前
danci 项目(三):从 JSON 数据到 AI Coding,真实项目里的数据清洗、Prompt 和工程规范
前端·后端·node.js
y = xⁿ5 小时前
DeepSeek Harness 学习日记:关于Agent接口,工具调用的底层实现
android·java·学习
东风破_5 小时前
danci 项目(一):从需求到架构,一个单词学习系统为什么会这样设计
前端·后端·node.js
侧耳倾听1116 小时前
jwt使用简介
java·jwt
顶点多余6 小时前
那些在算法中适合巩固的知识点---1
java·前端·算法
AI人工智能+电脑小能手6 小时前
大白话说Java设计模式-46-责任链模式(业务实战篇)
java·设计模式·责任链模式·风控校验·servlet filter·spring interceptor·链式处理
jay神7 小时前
【计算机毕业设计】基于SpringBoot的程序教学辅助系统
java·前端·vue.js·spring boot·后端·毕业设计·课程设计
2601_962066497 小时前
【Sql Server】Update中的From语句,以及常见更新操作方式
android·java·数据库
yaoxin5211238 小时前
507. Java 反射 - 在 BeanFactory 中实现依赖注入
java·开发语言
OPEN-F8 小时前
C++模板教程:变参模板、折叠表达式与SFINAE
java·开发语言·c++