学习JAVA语言,很多人会忽略一个知识点—JVM,即JAVA虚拟机。Java语言之所以可以跨平台一次编译到处运行的原因就是有JVM支持,JVM用的是C语言+汇编语言编写的一个程序,往下可以和运行虚拟机的不同电脑即不同平台的软硬件交互,往上是可以为Java语言的执行提供一个逻辑上完整的运行机器(顾名思义就是一台虚拟的机器,有模拟出来的内存,CPU等).只有清楚了解的JVM的结构和执行JAVA语言过程才能更升入了解Java语言的各种特性,提高编程能力,优化和解决程序出现的BUG。下面想看一张JVM的结构图:


首先,记住,JVM主要分三大块:
1栈(Stack)
2方法区(Method Area),又称为非堆(Non-Heap),原因后面会讲
3堆(Heap)

写到这里,我想大家先在心里默记这三块: JVM主体有三块

我想只要接触了JAVA语言一段时间,都应该知道JAVA源代码文件是.java结尾,经过编译程序处理后变成.class结尾的字节码文件。用工厂生产来打个比方。.java这种原料经过第一家叫做Compiler(编译器)的工厂处理,生产出了.class产品,.class产品就是JVM这家工厂的原料,这些原料用做什么呢?JVM对于所有原料有一套对所有原料都相同的规范(本文核心jvm内部处理原理)来处理,至于处理结果就不是简单打个比方,往控制台输出一行字,接收网络数据包等等,但这些不是本文叙述的范围,各位请忽略这点,不要分心。在这个工厂生产的类比中,原料有了,处理工厂有了,那原料一开始是放在很远的地方(硬盘中),怎么送到工厂能,那就需要一个运输工具 ,叫ClassLoader(类加载器),ClassLoader是JVM工厂的运输车队,负责把原料运输到工厂处理,这一块在本文不讲述。
下面就开始讲述ClassLoader把原料运输到JVM后发生的事。

  • 线程

    • JVM 系统线程
    • 每个线程相关的
    • 程序计数器
    • 本地栈
    • 栈限制
    • 栈帧
    • 局部变量数组
    • 操作数栈
    • 动态链接
  • 线程共享
    • 内存管理
    • 非堆内存
    • 即时编译
    • 方法区
    • 类文件结构
    • 类加载器
    • 更快的类加载
    • 方法区在哪里
    • 类加载器参考
    • 运行时常量池
    • 异常表
    • 符号表
    • Interned 字符串

线程

@SessionAttributes(value={"user"}, types={String.class})
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {private static final String SUCCESS = "success";@RequestMapping("/testRedirect")public String testRedirect(){System.out.println("testRedirect");return "redirect:/index.jsp";}@RequestMapping("/testView")public String testView(){System.out.println("testView");return "helloView";}@RequestMapping("/testViewAndViewResolver")public String testViewAndViewResolver(){System.out.println("testViewAndViewResolver");return SUCCESS;}/*** 1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用! * 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:* 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中.* 2). SpringMVC 会一 value 为 key, POJO 类型的对象为 value, 存入到 request 中. */@ModelAttributepublic void getUser(@RequestParam(value="id",required=false) Integer id, Map<String, Object> map){System.out.println("modelAttribute method");if(id != null){//模拟从数据库中获取对象User user = new User(1, "Tom", "123456", "tom@atguigu.com", 12);System.out.println("从数据库中获取一个对象: " + user);map.put("user", user);}}/*** 运行流程:* 1. 执行 @ModelAttribute 注解修饰的方法: 从数据库中取出对象, 把对象放入到了 Map 中. 键为: user* 2. SpringMVC 从 Map 中取出 User 对象, 并把表单的请求参数赋给该 User 对象的对应属性.* 3. SpringMVC 把上述对象传入目标方法的参数. * * 注意: 在 @ModelAttribute 修饰的方法中, 放入到 Map 时的键需要和目标方法入参类型的第一个字母小写的字符串一致!* * SpringMVC 确定目标方法 POJO 类型入参的过程* 1. 确定一个 key:* 1). 若目标方法的 POJO 类型的参数木有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写* 2). 若使用了  @ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的 value 属性值. * 2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入* 1). 若在 @ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的 key 一致, 则会获取到. * 3. 若 implicitModel 中不存在 key 对应的对象, 则检查当前的 Handler 是否使用 @SessionAttributes 注解修饰, * 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所* 对应的 value 值, 若存在则直接传入到目标方法的入参中. 若不存在则将抛出异常. * 4. 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则* 会通过反射来创建 POJO 类型的参数, 传入为目标方法的参数* 5. SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中. * * 源代码分析的流程* 1. 调用 @ModelAttribute 注解修饰的方法. 实际上把 @ModelAttribute 方法中 Map 中的数据放在了 implicitModel 中.* 2. 解析请求处理器的目标参数, 实际上该目标参数来自于 WebDataBinder 对象的 target 属性* 1). 创建 WebDataBinder 对象:* ①. 确定 objectName 属性: 若传入的 attrName 属性值为 "", 则 objectName 为类名第一个字母小写. * *注意: attrName. 若目标方法的 POJO 属性使用了 @ModelAttribute 来修饰, 则 attrName 值即为 @ModelAttribute * 的 value 属性值 * * ②. 确定 target 属性:*  > 在 implicitModel 中查找 attrName 对应的属性值. 若存在, ok*  > *若不存在: 则验证当前 Handler 是否使用了 @SessionAttributes 进行修饰, 若使用了, 则尝试从 Session 中* 获取 attrName 所对应的属性值. 若 session 中没有对应的属性值, 则抛出了异常. *  > 若 Handler 没有使用 @SessionAttributes 进行修饰, 或 @SessionAttributes 中没有使用 value 值指定的 key* 和 attrName 相匹配, 则通过反射创建了 POJO 对象* * 2). SpringMVC 把表单的请求参数赋给了 WebDataBinder 的 target 对应的属性. * 3). *SpringMVC 会把 WebDataBinder 的 attrName 和 target 给到 implicitModel. * 近而传到 request 域对象中. * 4). 把 WebDataBinder 的 target 作为参数传递给目标方法的入参. */@RequestMapping("/testModelAttribute")public String testModelAttribute(User user){System.out.println("修改: " + user);return SUCCESS;}/*** @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是 value 属性值),* 还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上使用的是 types 属性值)* * 注意: 该注解只能放在类的上面. 而不能修饰放方法. */@RequestMapping("/testSessionAttributes")public String testSessionAttributes(Map<String, Object> map){User user = new User("Tom", "123456", "tom@atguigu.com", 15);map.put("user", user);map.put("school", "atguigu");return SUCCESS;}/*** 目标方法可以添加 Map 类型(实际上也可以是 Model 类型或 ModelMap 类型)的参数. * @param map* @return*/@RequestMapping("/testMap")public String testMap(Map<String, Object> map){System.out.println(map.getClass().getName()); map.put("names", Arrays.asList("Tom", "Jerry", "Mike"));return SUCCESS;}/*** 目标方法的返回值可以是 ModelAndView 类型。 * 其中可以包含视图和模型信息* SpringMVC 会把 ModelAndView 的 model 中数据放入到 request 域对象中. * @return*/@RequestMapping("/testModelAndView")public ModelAndView testModelAndView(){String viewName = SUCCESS;ModelAndView modelAndView = new ModelAndView(viewName);//添加模型数据到 ModelAndView 中.modelAndView.addObject("time", new Date());return modelAndView;}/*** 可以使用 Serlvet 原生的 API 作为目标方法的参数 具体支持以下类型* * HttpServletRequest * HttpServletResponse * HttpSession* java.security.Principal * Locale InputStream * OutputStream * Reader * Writer* @throws IOException */@RequestMapping("/testServletAPI")public void testServletAPI(HttpServletRequest request,HttpServletResponse response, Writer out) throws IOException {System.out.println("testServletAPI, " + request + ", " + response);out.write("hello springmvc");
//      return SUCCESS;}/*** Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配, 自动为该对象填充属性值。支持级联属性。* 如:dept.deptId、dept.address.tel 等*/@RequestMapping("/testPojo")public String testPojo(User user) {System.out.println("testPojo: " + user);return SUCCESS;}/*** 了解:* * @CookieValue: 映射一个 Cookie 值. 属性同 @RequestParam*/@RequestMapping("/testCookieValue")public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) {System.out.println("testCookieValue: sessionId: " + sessionId);return SUCCESS;}/*** 了解: 映射请求头信息 用法同 @RequestParam*/@RequestMapping("/testRequestHeader")public String testRequestHeader(@RequestHeader(value = "Accept-Language") String al) {System.out.println("testRequestHeader, Accept-Language: " + al);return SUCCESS;}/*** @RequestParam 来映射请求参数. value 值即请求参数的参数名 required 该参数是否必须. 默认为 true*               defaultValue 请求参数的默认值*/@RequestMapping(value = "/testRequestParam")public String testRequestParam(@RequestParam(value = "username") String un,@RequestParam(value = "age", required = false, defaultValue = "0") int age) {System.out.println("testRequestParam, username: " + un + ", age: "+ age);return SUCCESS;}/*** Rest 风格的 URL. 以 CRUD 为例: 新增: /order POST 修改: /order/1 PUT update?id=1 获取:* /order/1 GET get?id=1 删除: /order/1 DELETE delete?id=1* * 如何发送 PUT 请求和 DELETE 请求呢 ? 1. 需要配置 HiddenHttpMethodFilter 2. 需要发送 POST 请求* 3. 需要在发送 POST 请求时携带一个 name="_method" 的隐藏域, 值为 DELETE 或 PUT* * 在 SpringMVC 的目标方法中如何得到 id 呢? 使用 @PathVariable 注解* */@RequestMapping(value = "/testRest/{id}", method = RequestMethod.PUT)public String testRestPut(@PathVariable Integer id) {System.out.println("testRest Put: " + id);return SUCCESS;}@RequestMapping(value = "/testRest/{id}", method = RequestMethod.DELETE)public String testRestDelete(@PathVariable Integer id) {System.out.println("testRest Delete: " + id);return SUCCESS;}@RequestMapping(value = "/testRest", method = RequestMethod.POST)public String testRest() {System.out.println("testRest POST");return SUCCESS;}@RequestMapping(value = "/testRest/{id}", method = RequestMethod.GET)public String testRest(@PathVariable Integer id) {System.out.println("testRest GET: " + id);return SUCCESS;}/*** @PathVariable 可以来映射 URL 中的占位符到目标方法的参数中.* @param id* @return*/@RequestMapping("/testPathVariable/{id}")public String testPathVariable(@PathVariable("id") Integer id) {System.out.println("testPathVariable: " + id);return SUCCESS;}@RequestMapping("/testAntPath/*/abc")public String testAntPath() {System.out.println("testAntPath");return SUCCESS;}/*** 了解: 可以使用 params 和 headers 来更加精确的映射请求. params 和 headers 支持简单的表达式.* * @return*/@RequestMapping(value = "testParamsAndHeaders", params = { "username","age!=10" }, headers = { "Accept-Language=en-US,zh;q=0.8" })public String testParamsAndHeaders() {System.out.println("testParamsAndHeaders");return SUCCESS;}/*** 常用: 使用 method 属性来指定请求方式*/@RequestMapping(value = "/testMethod", method = RequestMethod.POST)public String testMethod() {System.out.println("testMethod");return SUCCESS;}/*** 1. @RequestMapping 除了修饰方法, 还可来修饰类 2. 1). 类定义处: 提供初步的请求映射信息。相对于 WEB 应用的根目录* 2). 方法处: 提供进一步的细分映射信息。 相对于类定义处的 URL。若类定义处未标注 @RequestMapping,则方法处标记的 URL* 相对于 WEB 应用的根目录*/@RequestMapping("/testRequestMapping")public String testRequestMapping() {System.out.println("testRequestMapping");return SUCCESS;}}

这里所说的线程指程序执行过程中的一个线程实体。JVM 允许一个应用并发执行多个线程。Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的映射关系。当线程本地存储、缓冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程。Java 线程结束,原生线程随之被回收。操作系统负责调度所有线程,并把它们分配到任何可用的 CPU 上。当原生线程初始化完毕,就会调用 Java 线程的 run() 方法。run() 返回时,被处理未捕获异常,原生线程将确认由于它的结束是否要终止 JVM 进程(比如这个线程是最后一个非守护线程)。当线程结束时,会释放原生线程和 Java 线程的所有资源。
JVM 系统线程

如果使用 jconsole 或者其它调试器,你会看到很多线程在后台运行。这些后台线程与触发 public static void main(String[]) 函数的主线程以及主线程创建的其他线程一起运行。Hotspot JVM 后台运行的系统线程主要有下面几个:

虚拟机线程(VM thread) 这个线程等待 JVM 到达安全点操作出现。这些操作必须要在独立的线程里执行,因为当堆修改无法进行时,线程都需要 JVM 位于安全点。这些操作的类型有:stop-the-world 垃圾回收、线程栈 dump、线程暂停、线程偏向锁(biased locking)解除。
周期性任务线程 这线程负责定时器事件(也就是中断),用来调度周期性操作的执行。
GC 线程 这些线程支持 JVM 中不同的垃圾回收活动。
编译器线程 这些线程在运行时将字节码动态编译成本地平台相关的机器码。
信号分发线程 这个线程接收发送到 JVM 的信号并调用适当的 JVM 方法处理。

JAVA自我总结和分享—JVM相关推荐

  1. java培训面试技巧分享

    很多人在学会java技术之后,就开始筹备自己的面试了,java技术在互联网行业的需求是很大的,所以内卷是很严重的,在面试环节一定要全力以赴才行,下面小编就教大家一些java培训面试技巧,希望能帮助到大 ...

  2. Java 面试知识点解析(三)——JVM篇

    前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...

  3. Java跨平台实现原理及JVM垃圾回收、内存管理实战

    对象已死?啊,难受-- 最近深陷排查各种内存溢出.内存泄漏的问题,不得不对垃圾回收器下手了,因为当垃圾收集成为系统达到更高并发量的瓶颈时,我们就必须对这些"自动化"的技术实施必要的 ...

  4. 为什么虚拟机上一运行就显示程序停止_五分钟学Java:如何学习Java面试必考的JVM虚拟机...

    原创声明 本文首发于微信公众号[程序员黄小斜] 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 本文思维导图 为什么要学习JVM虚拟机 最近的你有没有参加Java面试呢?你有没有发现,Java ...

  5. 为什么虚拟机上一运行就显示程序停止_五分钟学Java:如何学习Java面试必考的JVM虚拟机||CSDN博文精选...

    作者:黄小斜 原创声明 本文作者:黄小斜 转载请务必在文章开头注明出处和作者. 本文思维导图 为什么要学习JVM虚拟机 最近的你有没有参加Java面试呢?你有没有发现,Java面试中总是爱考一类问题, ...

  6. JVM内存区域(Java内存区域)、JVM垃圾回收机制(GC)初探

    一.JVM内存区域(Java内存区域) 首先区分一下JVM内存区域(Java内存区域)和Java内存模型(JMM)的概念.Java线程之间的通信采用的是共享内存模型,这里提到的共享内存模型指的就是Ja ...

  7. 拒绝面试造火箭,工作拧螺丝——Java经典面试题分享『带答案』

    本文转载自:拒绝"面试造火箭,工作拧螺丝"--Java经典面试题分享『带答案』 1. Java三大版本 Java2平台包括标准版(J2SE).企业版(J2EE)和微缩版(J2ME) ...

  8. 阿里巴巴内部资料:2020最全Java技术栈PPT分享(架构篇+算法篇+大数据)

    我只截图不说话,PPT大全,氛围研发篇.算法篇.大数据.Java后端架构!除了大家熟悉的交易.支付场景外,支撑起阿里双十一交易1682亿元的"超级工程"其实包括以下但不限于客服.搜 ...

  9. java 12_Java 12在哪下载 Java 12下载地址分享

    Java 12在哪下载?Java 12于2019年3月20日正式发布,于上一个版本不同,Java 12是一个短期支持版本,但是Java 12并不是一个小版本,依然为各位带来了一些重大新功能,想要使用J ...

最新文章

  1. 你的接口能承受高并发吗?
  2. python numpy库安装winerror5_(转载)Numpy安装中遇到的问题和解决方法
  3. html的!DOCTYPE标签初窥
  4. Tensorboard--模型可视化工具
  5. 4月1日被愚了吗,我就看看你们都比较都喜欢哪些教程?
  6. poj3262(Protecting the Flowers)贪心
  7. 我给曾经暗恋的高中女同学,用Python实现了她飞机上刷抖音
  8. 【Vim命令大全】史上最全的Vim命令
  9. 顶级大厂如何做好暗黑模式设计?来看 Ant Design 的规范文档
  10. 树莓派Ubuntu20.04常见问题总结
  11. 中国电信php,一个基于中国电信开放应用平台的短信发送函数(PHP版)
  12. APP静默安装卸载管理器实现与上架到应用宝和豌豆荚
  13. 大数据 就业 缺口_大数据就业前景广阔,大数据人才紧缺,岗位缺口大
  14. Bezier曲线原理及实现代码(c++)
  15. Windows上解压缩版MySQL配置
  16. excel如何快速自动让空白单元格填充上一行内容
  17. 适合团队工作的软件,大家来看看有没有喜欢的吧
  18. 漂亮的css网站js资源无限下载
  19. LPTSTR、LPCSTR、LPCTSTR、LPSTR之间的转换
  20. Cocos2dx 使用obb扩展包

热门文章

  1. 在一台Ubuntu计算机上构建Hyperledger Fabric网络
  2. (Nowcoder) F.Popping Balloons
  3. Error:Execution failed for task ':xst:process开发环境DebugResources'.
  4. pyqt5 日历设计 QSS
  5. 在Ubuntu上为软件安装桌面快捷方式
  6. STL模型转点云数据
  7. 奥塔在线:CentOS7下配置Nginx实现本地缓存
  8. 阿里研究院第三届学术委员会成立,主席曾鸣畅谈未来学术生态构建
  9. 仿QQ空间的一款APP(二)
  10. python看门狗(watchdog)、多线程、实现文件夹实时监听、日志输出、备份