<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Java on Website of SauceWu</title><link>https://saucewu.github.io/tags/java/</link><description>Recent content in Java on Website of SauceWu</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Fri, 15 May 2020 00:00:00 +0000</lastBuildDate><atom:link href="https://saucewu.github.io/tags/java/index.xml" rel="self" type="application/rss+xml"/><item><title>JVM学习笔记（内存分区篇）</title><link>https://saucewu.github.io/posts/jvm%E5%86%85%E5%AD%98%E5%88%86%E5%8C%BA%E7%AC%94%E8%AE%B0/</link><pubDate>Fri, 15 May 2020 00:00:00 +0000</pubDate><guid>https://saucewu.github.io/posts/jvm%E5%86%85%E5%AD%98%E5%88%86%E5%8C%BA%E7%AC%94%E8%AE%B0/</guid><description>&lt;h1 id="jvm学习笔记内存分区篇"&gt;JVM学习笔记（内存分区篇）&lt;/h1&gt;
&lt;h1 id="概述"&gt;概述&lt;/h1&gt;
&lt;p&gt;&lt;img src="https://s1.ax1x.com/2020/05/15/YsPiX6.jpg" alt="YsPiX6.jpg"&gt;&lt;/p&gt;
&lt;h2 id="线程私有区"&gt;线程私有区&lt;/h2&gt;
&lt;p&gt;这三个区是随着线程生命周期创建销毁的。&lt;/p&gt;
&lt;h3 id="程序计数器"&gt;程序计数器&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;与CPU中程序计数器作用相同 ，用于记录当前线程程序现在运行到哪里。&lt;/li&gt;
&lt;li&gt;基于CPU的时间片轮转运行机制，CPU并不会把一个线程中的任务做完之后才切换线程，而是在不同线程中不停切换以达到并发的效果，所以我们需要记录下当切程序运行到的指令地址，在下一次轮到该线程执行时可以继续运行。&lt;/li&gt;
&lt;li&gt;Java虚拟机中的程序计数器仅仅是虚拟机中的，存在于内存之上的“&lt;strong&gt;虚拟&lt;/strong&gt;”计数器。&lt;/li&gt;
&lt;li&gt;要注意的是在运行native方法, 使用的是cpu的程序计数器 JVM中的程序计数器会被定义为undefined。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="可能产生的异常"&gt;可能产生的异常&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;因为程序计数器只是存储一个定长的指令地址，所以不会有OutOfMemoryError出现&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="虚拟机栈-本地方法栈"&gt;虚拟机栈 /本地方法栈&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;把这两个区的作用大致是一样的，只是Java虚拟机栈运行的是Java方法，本地方法栈运行的是native方法。而且在很多虚拟机(比如HotSpot VM)中把这两个栈融合成所谓的“&lt;strong&gt;mixed stack&lt;/strong&gt;”两种栈帧都可以储存。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;栈区是由栈帧组成的。当调用方法时，Java虚拟机将新建一个帧；方法退出时，帧将自动消除。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;线程运行过程中，只有一个栈帧是处于活跃状态，称为“&lt;strong&gt;当前活跃栈帧&lt;/strong&gt;”，当前活动栈帧始终是虚拟机栈的栈顶元素。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="栈帧"&gt;栈帧&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://s1.ax1x.com/2020/05/15/YsDwzF.jpg" alt="YsDwzF.jpg"&gt;&lt;/p&gt;
&lt;h5 id="局部变量表"&gt;局部变量表&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;在编译程序代码的时候就可以确定栈帧中需要多大的局部变量表，具体大小可在编译后的 Class 文件中看到。&lt;/li&gt;
&lt;li&gt;局部变量表的容量以&lt;strong&gt;Variable Slot&lt;/strong&gt;（变量槽）为最小单位，每个变量槽都可以存储 32 位长度的内存空间。&lt;/li&gt;
&lt;li&gt;在方法执行时，虚拟机使用局部变量表完成参数值到参数变量列表的传递过程的，如果执行的是实例方法，那局部变量表中第 0 位索引的 Slot 默认是用于传递方法所属对象实例的引用（在方法中可以通过关键字 this 来访问到这个隐含的参数）。&lt;/li&gt;
&lt;li&gt;其余参数则按照参数表顺序排列，占用从 1 开始的局部变量 Slot。&lt;/li&gt;
&lt;li&gt;基本类型数据以及引用和 returnAddress（返回地址）占用一个变量槽，long 和 double 需要两个。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="操作数栈"&gt;操作数栈&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;同样也可以在编译期确定大小。&lt;/li&gt;
&lt;li&gt;Frame 被创建时，操作栈是空的。操作栈的每个项可以存放 JVM 的各种类型数据，其中 long 和 double 类型（64位数据）占用两个栈深。&lt;/li&gt;
&lt;li&gt;方法执行的过程中，会有各种字节码指令往操作数栈中写入和提取内容，也就是出栈和入栈操作（与 Java 栈中栈帧操作类似）。&lt;/li&gt;
&lt;li&gt;操作栈调用其它有返回结果的方法时，会把结果 push 到栈上（通过操作数栈来进行参数传递）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="动态链接"&gt;动态链接&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用，持有这个引用是为了支持方法调用过程中的动态链接。&lt;/li&gt;
&lt;li&gt;在类加载阶段中的解析阶段会将符号引用转为直接引用，这种转化也称为静态解析。另外的一部分将在运行时转化为直接引用，这部分称为动态链接。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="返回地址"&gt;返回地址&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;方法开始执行后，只有 2 种方式可以退出 ：方法返回指令，异常退出。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="可能产生的异常-1"&gt;可能产生的异常&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;线程请求分配的栈容量&amp;gt;Java虚拟机最大栈容量，则JVM会抛出StackOverFlowError异常。&lt;/p&gt;</description></item></channel></rss>