【JVM基础知识及实战项目思考和总结】

基础知识

JVM内存结构

  • 堆(Heap):存储对象实例和数组。
  • 方法区(Method Area):存储类信息、常量、静态变量等。
  • 程序计数器(Program Counter):当前线程所执行的字节码的行号指示器。
  • 虚拟机栈(VM Stack):每个方法执行时都会创建一个栈帧,用于存储局部变量和操作数栈。
  • 本地方法栈(Native Method Stack):为Native方法服务。

类加载机制

  • 加载(Loading):将.class文件加载到内存中。
  • 验证(Verification):确保加载的类信息符合JVM规范。
  • 准备(Preparation):为类的静态变量分配内存,并设置默认初始值。
  • 解析(Resolution):将符号引用转换为直接引用。
  • 初始化(Initialization):执行类构造器()方法。
按需加载

Java类的加载发生在首次主动使用该类时,这被称为"按需加载"。"主动使用"包括以下几种情况:

  1. 创建类的实例。
  2. 访问类中的静态字段(不是静态方法)。
  3. 调用类的静态方法。
  4. 使用 java.lang.reflect 包的方法主动引用类。
  5. 初始化某个类的子类。
  6. 其他一些隐式的引用,比如接口实现、异常处理等。

项目思考

项目中的工具类(没有被spring管理的),static代码块是否是项目启动时就执行的?

项目中使用到了RestTemplate,并封装了工具类,部分代码如下

RestUtil.java

java 复制代码
public class RestUtil {

    //代码省略

    /**
     * RestAPI 调用器
     */
    private final static RestTemplate RT;

    static {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(30000);
        requestFactory.setReadTimeout(4000000);
        RT = new RestTemplate(requestFactory);
        // 解决乱码问题
        RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        // 新增个性化日志
        List<ClientHttpRequestInterceptor> interceptors = Optional.ofNullable(RT.getInterceptors()).orElse(new ArrayList<>());
        // 优化直接获取bean 抛异常的写法
        //获取自定义拦截器
        Map<String, RestTemplateLogInterceptor> beans = SpringContextUtils.getApplicationContext().getBeansOfType(RestTemplateLogInterceptor.class);
        if(!CollectionUtils.isEmpty(beans)){
            beans.forEach((k, v) -> interceptors.add(v));
        }
        RT.setInterceptors(interceptors);
    }
	//代码省略

    public static <T> ResponseEntity<T> request(String url, HttpMethod method, HttpHeaders headers, JSONObject variables, JSONObject params, Class<T> responseType) {
       	...
        return RT.exchange(url, method, request, responseType);
    }  
}
答: 不是项目启动时执行的,是调用RestUtil.request 方法的时候执行的。

总结:上述代码并没有被spring管理,并且没有符合"按需加载"的所有条件,所以当项目启动完成后,RestUtil这个类并没有被JVM加载到内存里,也就意味着这个类并没有执行"类加载过程"。

测试验证

先建springboot项目结构如图

TestUtil.java

java 复制代码
public class TestUtil {

    private static List<String> testList = new ArrayList<>();

    private static String name;

    static {
        for (int i = 0; i < 1000000; i++) {
            testList.add("test" + i);
        }
    }

    public static void setName(String name) {
        TestUtil.name = name;
    }
}

TestController.java

java 复制代码
@RestController
public class TestController {
    @GetMapping("/status")
    public String status() {
        TestUtil.setName("xxx");
        return "ok";
    }
}
代码说明:
  • 工具类的setName方法只是为了把此类加载到内存中,来验证项目思考的内容。
接下来是使用jvisualvm工具对堆空间变化的截图
相关推荐
兵慌码乱7 小时前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理
金銀銅鐵9 小时前
[Python] 体验用欧几里得算法计算最大公约数的过程
python·数学
FreakStudio13 小时前
W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
用户03321266636714 小时前
使用 Python 从零创建 Word 文档
python
Csvn19 小时前
Python 两大经典坑点 —— 可变默认参数 & 闭包延迟绑定
后端·python
曲幽20 小时前
别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了
python·docker·web·pot·translate·libretranslate·arogstranslate
用户5569188175321 小时前
#从脚本到独立程序:Python + Playwright 批量抓取的完整踩坑记录
python·自动化运维
兵慌码乱1 天前
基于 MediaPipe 与 PySide2 的手势交互音乐控制系统实现:轻量化视觉交互全流程解析
python·opencv·计算机视觉·人机交互·手势识别·mediapipe·pyside2
luckdewei2 天前
FastAPI 资产管理系统实战:复杂 ORM 关联、Alembic 迁移与 N+1 查询优化
python