Java全栈解密:从JVM内存管理到Spring框架,揭秘垃圾回收、类加载机制与Web开发精髓的全方位旅程
JVM内存划分
在JVM中,每个线程有自己的虚拟机栈,而整个JVM实例共享一些内存区域。JVM的内存划分主要包括四个部分:程序计数器、虚拟机栈、堆区和方法区(元数据区)。
-
程序计数器:程序计数器用于存储当前线程所执行的字节码指令的地址。在程序执行过程中,程序计数器会随着指令的执行而递增,如果遇到条件分支、循环等控制结构时,程序计数器的值也会发生变化。
-
虚拟机栈:每个线程都有自己的虚拟机栈,栈内存储的是栈帧。栈帧包含方法的局部变量表、操作数栈、动态链接、方法出口等信息。每当一个方法被调用时,JVM都会在虚拟机栈中创建一个新的栈帧。当方法执行结束时,栈帧会被弹出。
-
堆区:堆区是JVM内存中最大的一块区域,用于存储通过
new关键字创建的对象和数组。所有线程共享堆区,是垃圾回收器管理的主要区域。 -
方法区(元数据区):方法区用于存储类的元数据、常量、静态变量和即时编译后的代码。虽然方法区是堆的一部分,但它有一个别名叫做“非堆”。
需要注意的是,程序计数器和虚拟机栈是线程私有的,而堆区和方法区是所有线程共享的。
class Student {// 类的定义
}public class People {public static void main(String[] args) {Student s = new Student();// s变量是一个局部变量,位于虚拟机栈中// s指向的Student对象位于堆区}
}
在上述代码中,s变量是一个局部变量,位于虚拟机栈中。s指向的Student对象实际存储在堆区中。
类加载
Java代码需要解析为.class文件,并通过JVM读取.class文件创建类对象,将其加载到方法区。类加载可以细分为以下五个步骤:加载、验证、准备、解析和初始化。
-
加载:将.class文件中的二进制数据加载到JVM中,将这些数据映射为方法区中的类对象。这一步通常包括从文件系统、网络或其他源读取.class文件。
-
验证:验证.class文件的字节码是否符合JVM的规范,确保没有安全威胁或格式错误。这一步的主要目的是保护虚拟机免受恶意代码的攻击。
-
准备:为类的静态变量分配内存,并将其初始化为默认值(通常为零或null)。此时只分配内存,不进行任何赋值操作。
-
解析:将常量池中的符号引用转换为直接引用。符号引用是用来表示类、接口、字段和方法的符号表项,通过解析将其转换为具体的内存地址或偏移量。符号引用在类加载时并不会直接指向具体内存,解析步骤将其替换为可以直接访问的内存地址或偏移量。
-
初始化:对类的静态变量赋予初始值,并执行静态初始化块。如果类中定义了静态变量且有初始值,则在此阶段赋予变量这些初始值。随后,执行类的静态代码块(如果有),以完成类的初始化工作。
通过上述五个步骤,JVM能够确保.class文件中的字节码被正确加载并转换为可以执行的Java类,确保代码的安全性和正确性。
双亲委派模型
双亲委派模型是Java虚拟机(JVM)类加载机制中使用的一种模式。这种模型有助于保证核心类的安全性,防止类的重复加载,并且实现分层管理。
-
保证核心类的安全性:类加载过程会优先由父类加载器进行。根类加载器(Bootstrap ClassLoader)会首先尝试加载Java的核心类库,这样可以确保这些核心类不会被其他恶意类加载器篡改。
-
防止类的重复加载:当一个类加载器尝试加载某个类时,它会首先检查缓存区是否已经加载过该类。如果缓存中不存在该类,类加载请求会逐级向上委派给父类加载器,直到到达根类加载器(Bootstrap ClassLoader)。如果根类加载器已经加载过该类,它将直接返回该类的引用。否则,类加载过程会返回一个ClassNotFoundException,通知子类加载器继续尝试加载。
-
分层管理:通过使用双亲委派模型,可以实现类加载的分层管理。自定义类和核心类等会被不同的类加载器加载,避免了相互干扰。核心类由根类加载器加载,而自定义类通常由应用程序类加载器或自定义类加载器加载。
具体过程如下:类加载请求首先会被委派给父类加载器,直至到达根类加载器(Bootstrap ClassLoader)。如果根类加载器能够找到对应的类,则进行加载并返回。如果根类加载器找不到该类,会抛出ClassNotFoundException,并将异常传递给子类加载器,子类加载器依次尝试加载该类,直到由自定义类加载器进行处理。
通过这种方式,双亲委派模型有效地确保了Java应用程序中类加载的安全性、可靠性和灵活性。
垃圾回收机制
JVM的垃圾回收机制(GC)是用来管理内存的分配和释放的。当GC发现不再被使用的对象(垃圾)时,会自动释放它们占用的内存空间。
对象扫描起点
JVM会从GC Roots(例如静态变量、栈中的引用、本地方法栈中的引用等)开始,对所有对象进行扫描,以确定哪些对象是可达的(仍被使用的),哪些对象是不可达的(垃圾)。
JVM堆的划分
JVM的堆分为以下几部分:
-
新生代(Young Generation):
- 伊甸区(Eden Space):存放新创建的对象。
- 存活区(Survivor Spaces):用来存放从Eden区复制和存活下来的对象,分为两个部分——From Survivor和To Survivor。存活的对象被复制到To Survivor,然后清空From Survivor。
-
老年代(Old Generation):存放从新生代中筛选出来的、多次GC后仍未被清除的长生命周期对象。
-
元空间(Metaspace,JDK 8及以后):存放类的元数据,如类定义、方法、静态数据等信息。JDK 8之前称为永久代(Permanent Generation)。
清除方式
-
标记-清除(Mark-Sweep):
- 标记阶段:从GC Roots开始,标记所有可达对象。
- 清除阶段:清除所有未标记的对象,释放它们的内存。
- 缺点:容易产生内存碎片,导致内存难以管理和分配。
-
复制算法(Copying):
- 过程:将内存划分为两个等大小的区域。首先将所有对象分配到其中一个区域,当该区域内存用尽时,对该区域进行扫描,将所有存活的对象复制到另一个区域,然后清空第一个区域。
- 优点:消除了内存碎片。
- 缺点:需要两倍的内存空间,浪费了一部分内存。
-
标记-整理(Mark-Compact):
- 标记阶段:从GC Roots开始,标记所有可达对象。
- 整理阶段:将所有存活的对象移动到内存的一端,压缩内存空间,消除碎片。
- 优点:解决了内存碎片问题,内存利用率更高。
通过这些方式,JVM的垃圾回收机制能够有效管理内存,自动释放不再使用的对象,确保内存资源的合理利用。不同的GC算法和策略有其适用场景和优缺点,开发者可以根据具体应用需求选择合适的GC策略。
this关键字
this关键字的含义
this关键字在Java中用于引用当前对象。它有几个不同的用法,具体取决于上下文:
- 在构造方法中:this表示正在创建的对象。
- 在成员方法中:this表示调用该方法的当前对象。
this关键字的作用
this关键字主要用于以下几个方面:
-
区分局部变量和成员变量: 在方法或构造方法中,局部变量和成员变量如果同名,可以使用this关键字来区分它们。
-
调用类的其他构造方法: 在一个构造方法中,可以通过this关键字调用同一类中的其他构造方法,以减少代码重复。
-
返回当前对象: this关键字还可以用来返回当前对象的引用,通常用于链式调用。
总之,this关键字在Java中是一个非常重要的概念,它的正确使用可以使代码更加清晰和易于维护。
匿名对象
匿名对象是指没有被任何变量引用的对象。这种对象在创建后立即使用,并在使用完毕后被垃圾回收。
匿名对象的作用
-
使用匿名对象调用方法: 匿名对象可以直接用于调用方法,而无需先声明一个变量来引用该对象。
-
使用匿名对象作为参数传入方法: 匿名对象可以直接作为参数传递给方法,这在需要临时对象时非常有用。
-
匿名对象作为方法的返回值: 方法可以返回一个匿名对象,在需要立即使用返回对象而不需要长期保存引用时非常方便。
匿名对象的使用使得代码更加简洁,特别是在仅需要临时对象的场景中。由于这些对象没有被任何变量引用,它们在使用后会很快被垃圾回收,从而提高内存利用效率。
Spring框架
Spring是面向企业级的Java开发框架,其主要特点是IOC(控制反转)、DI(依赖注入)和面向切面的编程。由于基于Java的特性,Spring具有广泛的部署平台。
- IOC(控制反转):将对象的创建和管理交给Spring框架,降低对象之间的耦合性。
- 事务处理:Spring框架能够将系统和事务进行分离,使得事务处理适合在多平台上进行。
- DI(依赖注入):通过依赖注入机制,Spring可以方便地读取和管理对象,以进行业务处理。
Spring 常见的注解:
-
@Component:用于标记一个类,使其能够被 Spring 容器管理。所有其他的 Spring 注解(例如 @Service、@Controller 等)都基于 @Component,因此它是这些注解的基础。
-
@Controller:用于标记一个类,使其能够被 Spring MVC 框架管理,通常用于定义控制器类。
-
@Service:用于标记一个类,表示该类是处理业务逻辑的服务组件。
-
@Repository:用于标记一个类,表示该类是数据访问组件,通常用于与数据库交互。
-
@PathVariable:用于从 URL 路径中动态获取变量值,用于 RESTful 风格的接口中。
-
@Bean:用于方法上,表示该方法的返回值应该注册为 Spring 容器中的一个 Bean,以便于依赖注入。
Spring 框架采用了 Inversion of Control(IoC)模式来实现对象的创建和管理,并通过 Dependency Injection(DI)来进行对象的依赖注入。利用 Aspect-Oriented Programming(AOP)技术,Spring 使得业务逻辑和系统服务(如事务管理、日志记录等)能够分离,从而简化了业务处理的实现。
Spring 集成了许多流行的框架,例如 MyBatis,提供了更强大的数据持久化功能和更灵活的 SQL 映射配置。
此外,Spring 还提供了便捷的测试方案,使得开发者能够更方便地编写单元测试和集成测试,提高了代码的可维护性和可靠性。
JavaWeb
Servlet生命周期
Servlet的生命周期主要包含三个阶段:初始化、服务和销毁。以下是对每个阶段的详细说明:
1. 初始化
- 触发时机:
- Servlet加载到内存时
- 可通过
web.xml中的<load-on-startup>元素配置加载方式:- 正数:预加载,数字越小优先级越高
- 负数、0或不配置:懒加载(首次请求时加载)
- 执行过程:
- 调用
init()方法 - 在整个生命周期中只执行一次
- 调用
2. 服务
- 功能:处理客户端的各种请求
- 过程:
- 接收请求(如HTTP请求)
- 调用相应的处理方法(如
doGet()、doPost()等)
- 特点:每收到一个新请求就会执行一次
3. 销毁
- 触发时机:
- 手动调用销毁方法
- 服务器关闭
- 执行过程:
- 调用
destroy()方法 - 在整个生命周期中只执行一次
- 调用
生命周期流程
- 用户首次发送请求或服务器启动
- Servlet初始化
- 用户持续发送请求,Servlet处理请求(服务阶段)
- Servlet不再使用或服务器关闭时,Servlet被销毁
通过这个生命周期,Servlet能够高效地处理客户端请求,并合理管理资源。
forward()和redirect()
Forward和Redirect都用于在服务器处理后将请求或响应转发到另一个资源。
Forward方法
- 在服务器内部进行,URL不变
- 速度较快(服务器内部传输)
- 请求和响应数据共享,修改会影响接收方
Redirect方法
- 客户端接收含新URL的响应,发起新请求
- 速度较慢(涉及客户端与服务器交互)
- 不保留原请求数据
应用场景
- Forward示例: 未登录用户浏览商品 → 转发到登录页面 (保留浏览信息,便于登录后继续操作)
- Redirect示例: 浏览商品 → 重定向到订单确认页面 (URL变化,便于使用浏览器返回功能)
Request.getParameter() 与 Request.getAttribute() 的比较
Request.getParameter()
- 用途:用于获取客户端发送的参数。
- 场景:例如在登录界面,获取用户输入的账号和密码。
- 特点:直接获取HTTP请求中的参数值。
Request.getAttribute()
- 用途:用于获取请求范围内的数据。
- 场景:在请求处理过程中,在不同阶段之间传递数据。
- 特点:
- 需要先使用
setAttribute()设置数据。 - 然后可以在后续的处理阶段或JSP页面中使用
getAttribute()获取数据。
- 需要先使用
主要区别
- 数据来源:
getParameter(): 获取客户端发送的数据。getAttribute(): 获取服务器端设置的数据。
- 使用目的:
getParameter(): 用于接收客户端输入。getAttribute(): 用于服务器端不同处理阶段之间的数据共享。
- 数据生命周期:
getParameter(): 仅在当前请求中有效。getAttribute(): 可以在整个请求处理过程中共享。
使用示例
假设有一个登录功能:
- 客户端发送登录请求,包含用户名和密码。
- 服务器端处理:
// 获取客户端参数 String username = request.getParameter("username"); String password = request.getParameter("password");// 验证逻辑...// 设置属性以供后续使用 request.setAttribute("user", authenticatedUser); - 在后续的处理中(如转发到欢迎页面):
// 获取之前设置的属性 User user = (User) request.getAttribute("user");
这样,getAttribute()允许我们在整个请求处理过程中传递和共享数据,而不仅限于初始的客户端参数。
JSP的包含
JSP包含分为两种:静态包含(编译时包含)和动态包含(运行时包含)。它们在工作方式和执行时间上有所不同。
- 静态包含:
- 使用JSP指令: <%@ include file="file.jsp" %>
- 在编译时将被包含的页面合并到主页面中
- 作为整体一起编译,运行时不会发生变化
- 适用于内容相对固定的页面部分,如网站的头部和尾部
- 动态包含:
- 使用JSP动作: <jsp:include page="file.jsp" />
- 在请求处理期间(运行时)包含目标页面
- 每次请求都会重新编译被包含的页面,确保获取最新内容
- 适用于需要实时更新的内容,如天气信息或动态新闻
示例应用:
- 网页布局: 使用静态包含处理固定的页面结构(如头部、导航栏、尾部)
- 动态内容: 使用动态包含处理需要频繁更新的内容区域(如天气预报、实时新闻)
相关文章:
Java全栈解密:从JVM内存管理到Spring框架,揭秘垃圾回收、类加载机制与Web开发精髓的全方位旅程
JVM内存划分 在JVM中,每个线程有自己的虚拟机栈,而整个JVM实例共享一些内存区域。JVM的内存划分主要包括四个部分:程序计数器、虚拟机栈、堆区和方法区(元数据区)。 程序计数器:程序计数器用于存储当前线程…...
【探索Linux】P.46(高级IO —— 五种IO模型简介 | IO重要概念)
阅读导航 引言一、五种IO模型1. 阻塞IO(1)定义(2)特点 2. 非阻塞IO(1)定义(2)特点 3. IO多路复用(1)定义(2)特点 4. 信号驱动IO&#…...
【MongoDB 】MongoDB 介绍及应用,设计到4个案例
MongoDB 介绍概述 基础概念 MongoDB 是非关系型数据库,也就是nosql,存储json数据格式会非常灵活,要比数据库mysql/MariaDB更好,同时也能为mysql/MariaDB分摊一部分的流量压力。 对于经常读写的数据他会存入内存,如此…...
AI浪潮下的程序员生存指南:如何在智能时代锻造不可替代的核心竞争力
人工智能时代,程序员如何保持核心竞争力? 随着AIGC(如chatgpt、midjourney、claude等)大语言模型接二连三的涌现,AI辅助编程工具日益普及,程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工…...
Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC]
文章目录 Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关技术…...
vue 日期控件 100天内的时间禁用不允许选择
vue 日期控件 100天内的时间禁用不允许选择,可以从101天选起 比如,2024年8月9号开始,100天内禁止选择,第101天之后的日期可以选,效果如图所示 // 日期控件代码 加上 :picker-options"pickerOptions" <…...
服务器HTTP响应头安全性优化与漏洞修复方案
在对服务器进行漏洞扫描后,通常会发现一些常见的安全漏洞,特别是涉及HTTP响应头的问题。以下是本次扫描过程中发现的漏洞问题以及对应的修复方案 1.X-Content-Type-Options 响应头缺失 描述: 缺失此响应头可能导致浏览器错误地解析资源类型,存在MIME类型混淆攻击的风险。 …...
4.定时器(TIMER)
理论 预分频寄存器(TIMx_PSC):由于时钟源为:72MHz,T 1/f 1/72MHz,由于不好计算周期时间,则需要分频,若分72则T 1/1MHz 1us(1MHz 一百万秒) 计数方式:向上(递增到某个数触发中断)、向下(递…...
java springboot mqtt控制海康摄像头
GHHKControlService 接口 package org.gh.ghhk.service;public interface GHHKControlService {boolean monitorControl(String payload);}GHHKControlServiceImpl 实现类 package org.gh.ghhk.service.impl;import com.alibaba.fastjson.JSONArray; import com.alibaba.…...
AI大模型02:Prompt Engineering 提示工程
一、什么是提示工程(Prompt Engineering) 1.提示工程,也叫“指令工程” (1)Prompt 就是我们给大模型发送的指令,或者说是在聊天对话框中发送的内容。 Prompt是AGI时代的编程语言。 Prompt是去控制大模型的…...
EasyExcel动态表头导出
1、封装方法 package com.skybird.iot.base.utils;import cn.hutool.core.util.StrUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.w…...
可视化基础的设计四大原则
一个好的数据可视化设计可以帮助观众迅速理解数据背后的意义。然而,如何确保我们的可视化设计既美观又简单易懂呢?本文将介绍四大设计原则——亲密原则、对比原则、对齐原则和重复原则。 1、 亲密原则(Proximity) 定义与应用&am…...
MySQL基础练习题27-上升的温度
目录 题目 准备数据 分析数据 总结 题目 找出与之前(昨天的)日期相比温度更高的所有日期的 id 。 准备数据 ## 创建库 create database db; use db;## 创建表 Create table If Not Exists Weather (id int, recordDate date, temperature int);#…...
只出现一次的数字 II
给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。 示例 1: 输入:nums [2,2,3,2]…...
第十一章 数据仓库和商务智能 10分
11.1.0语境关系图 11.1 Q 建立数据仓库,有哪些步骤?如何建设?【6 个步骤非常重要!必须知道】 1. 理解需求(P)(目的明确,ETL) (1) 考虑业务目标和业务战略。 (2) 确定业…...
一篇文章带你解析完整数据结构-----满满干活值得收藏
数据结构是计算机科学中的一个重要分支,它涉及到计算机存储、组织数据的方式。以下是数据结构的主要知识点: 基本概念 数据(Data)。数据元素(Data Element):数据项(Data Item)&…...
11.3 用Python处理常见文件
欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏: 工💗重💗hao💗:野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题.…...
Linux知识复习第2期
RHCE 远程登录服务-CSDN博客 Linux 用户和组管理_linux用户和组的管理-CSDN博客 Linux 文件权限详解-CSDN博客 目录 1、sshd 免密登录 (1)纯净实验环境 (2)生成密钥 (3)上锁 2、用户管理 (1)添加新用户 (2)删除用户 (3)修改用户信息 (4)为用户账号设…...
驗證HTTP代理的有效性的方法和步驟-okeyproxy
如何驗證HTTP代理的有效性,確保它的性能和安全性,是非常必要的。本文將詳細介紹驗證HTTP代理有效性的方法和步驟。 HTTP代理作為一種仲介伺服器,它可以幫助用戶在訪問目標網站時隱藏真實IP地址,從而提高匿名性和安全性。通過HTTP…...
Java和kotlin 反射机制
Java 反射机制详解 Java 反射机制是一种强大的工具,使得程序可以在运行时动态地获取类的信息,并且可以在运行时操作类的成员变量、方法和构造函数等。以下是 Java 反射的详细讲解,包括其原理、使用场景、优缺点以及如何使用反射。 1. 反射的…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...
FTXUI::Dom 模块
DOM 模块定义了分层的 FTXUI::Element 树,可用于构建复杂的终端界面,支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...
