Skip to content

Commit e8d1667

Browse files
author
wangyueyang
committed
笔记
0 parents  commit e8d1667

2 files changed

Lines changed: 357 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"������һЩ�ʼ�"

‎java/javaclass.html‎

Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
5+
<head>
6+
<title>Javaclass文件结构说明</title>
7+
<!-- 2017-09-17 周日 11:05 -->
8+
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
9+
<meta name="generator" content="Org-mode" />
10+
<meta name="author" content="王月阳" />
11+
<meta name="description" content="对Java编译生成的class文件中,local,stack的含义和Java字节码的运行过程做一些说明。"
12+
/>
13+
<meta name="keywords" content="JAVA CLASS 运行时栈帧 操作数栈 编译器 解释运行 后缀表达式" />
14+
<style type="text/css">
15+
<!--/*--><![CDATA[/*><!--*/
16+
.title { text-align: center; }
17+
.todo { font-family: monospace; color: red; }
18+
.done { color: green; }
19+
.tag { background-color: #eee; font-family: monospace;
20+
padding: 2px; font-size: 80%; font-weight: normal; }
21+
.timestamp { color: #bebebe; }
22+
.timestamp-kwd { color: #5f9ea0; }
23+
.right { margin-left: auto; margin-right: 0px; text-align: right; }
24+
.left { margin-left: 0px; margin-right: auto; text-align: left; }
25+
.center { margin-left: auto; margin-right: auto; text-align: center; }
26+
.underline { text-decoration: underline; }
27+
#postamble p, #preamble p { font-size: 90%; margin: .2em; }
28+
p.verse { margin-left: 3%; }
29+
pre {
30+
border: 1px solid #ccc;
31+
box-shadow: 3px 3px 3px #eee;
32+
padding: 8pt;
33+
font-family: monospace;
34+
overflow: auto;
35+
margin: 1.2em;
36+
}
37+
pre.src {
38+
position: relative;
39+
overflow: visible;
40+
padding-top: 1.2em;
41+
}
42+
pre.src:before {
43+
display: none;
44+
position: absolute;
45+
background-color: white;
46+
top: -10px;
47+
right: 10px;
48+
padding: 3px;
49+
border: 1px solid black;
50+
}
51+
pre.src:hover:before { display: inline;}
52+
pre.src-sh:before { content: 'sh'; }
53+
pre.src-bash:before { content: 'sh'; }
54+
pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
55+
pre.src-R:before { content: 'R'; }
56+
pre.src-perl:before { content: 'Perl'; }
57+
pre.src-java:before { content: 'Java'; }
58+
pre.src-sql:before { content: 'SQL'; }
59+
60+
table { border-collapse:collapse; }
61+
caption.t-above { caption-side: top; }
62+
caption.t-bottom { caption-side: bottom; }
63+
td, th { vertical-align:top; }
64+
th.right { text-align: center; }
65+
th.left { text-align: center; }
66+
th.center { text-align: center; }
67+
td.right { text-align: right; }
68+
td.left { text-align: left; }
69+
td.center { text-align: center; }
70+
dt { font-weight: bold; }
71+
.footpara:nth-child(2) { display: inline; }
72+
.footpara { display: block; }
73+
.footdef { margin-bottom: 1em; }
74+
.figure { padding: 1em; }
75+
.figure p { text-align: center; }
76+
.inlinetask {
77+
padding: 10px;
78+
border: 2px solid gray;
79+
margin: 10px;
80+
background: #ffffcc;
81+
}
82+
#org-div-home-and-up
83+
{ text-align: right; font-size: 70%; white-space: nowrap; }
84+
textarea { overflow-x: auto; }
85+
.linenr { font-size: smaller }
86+
.code-highlighted { background-color: #ffff00; }
87+
.org-info-js_info-navigation { border-style: none; }
88+
#org-info-js_console-label
89+
{ font-size: 10px; font-weight: bold; white-space: nowrap; }
90+
.org-info-js_search-highlight
91+
{ background-color: #ffff00; color: #000000; font-weight: bold; }
92+
/*]]>*/-->
93+
</style>
94+
<script type="text/javascript">
95+
/*
96+
@licstart The following is the entire license notice for the
97+
JavaScript code in this tag.
98+
99+
Copyright (C) 2012-2013 Free Software Foundation, Inc.
100+
101+
The JavaScript code in this tag is free software: you can
102+
redistribute it and/or modify it under the terms of the GNU
103+
General Public License (GNU GPL) as published by the Free Software
104+
Foundation, either version 3 of the License, or (at your option)
105+
any later version. The code is distributed WITHOUT ANY WARRANTY;
106+
without even the implied warranty of MERCHANTABILITY or FITNESS
107+
FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
108+
109+
As additional permission under GNU GPL version 3 section 7, you
110+
may distribute non-source (e.g., minimized or compacted) forms of
111+
that code without the copy of the GNU GPL normally required by
112+
section 4, provided you include this license notice and a URL
113+
through which recipients can access the Corresponding Source.
114+
115+
116+
@licend The above is the entire license notice
117+
for the JavaScript code in this tag.
118+
*/
119+
<!--/*--><![CDATA[/*><!--*/
120+
function CodeHighlightOn(elem, id)
121+
{
122+
var target = document.getElementById(id);
123+
if(null != target) {
124+
elem.cacheClassElem = elem.className;
125+
elem.cacheClassTarget = target.className;
126+
target.className = "code-highlighted";
127+
elem.className = "code-highlighted";
128+
}
129+
}
130+
function CodeHighlightOff(elem, id)
131+
{
132+
var target = document.getElementById(id);
133+
if(elem.cacheClassElem)
134+
elem.className = elem.cacheClassElem;
135+
if(elem.cacheClassTarget)
136+
target.className = elem.cacheClassTarget;
137+
}
138+
/*]]>*///-->
139+
</script>
140+
</head>
141+
<body>
142+
<div id="content">
143+
<h1 class="title">Javaclass文件结构说明</h1>
144+
<div id="table-of-contents">
145+
<h2>Table of Contents</h2>
146+
<div id="text-table-of-contents">
147+
<ul>
148+
<li><a href="#sec-1">1. 前言</a></li>
149+
<li><a href="#sec-2">2. JVM解释运行过程</a></li>
150+
<li><a href="#sec-3">3. class文件结构说明</a>
151+
<ul>
152+
<li><a href="#sec-3-1">3.1. stack</a></li>
153+
<li><a href="#sec-3-2">3.2. locals</a></li>
154+
<li><a href="#sec-3-3">3.3. arg_size</a></li>
155+
</ul>
156+
</li>
157+
<li><a href="#sec-4">4. 结论</a></li>
158+
</ul>
159+
</div>
160+
</div>
161+
162+
163+
<div id="outline-container-sec-1" class="outline-2">
164+
<h2 id="sec-1"><span class="section-number-2">1</span> 前言</h2>
165+
<div class="outline-text-2" id="text-1">
166+
<p>
167+
这篇文章是基于读者对Java,编译原理,jvm规范有一定了解后书写的。对上述知识缺乏了解的可参考<a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">jvm规范,第四章</a> 改章节对class文件结构,jvm字节码质量有详细描述。
168+
</p>
169+
<hr />
170+
<p>
171+
+本文中主要使用到的字节码指令有
172+
-dup:复制栈顶数据并重新压入栈
173+
-iload:将int型数值压入栈
174+
-iadd:加法运算,需要两个参数
175+
-iconst_1:将int类型1压入栈
176+
-istore:将栈顶int值存到本地变量中
177+
-new:创建一个对象,并将引用值压入栈
178+
-invokervirtual:调用实例方法
179+
+本文中使用的Java命令有
180+
-javac:Java语言编译命令,将java源文件编译成虚拟机可执行的class文件
181+
-javap:Java反编译命令,讲class文件反编译成Java文件,或通过-verbose参数查看class文件结构
182+
</p>
183+
<hr />
184+
</div>
185+
</div>
186+
187+
<div id="outline-container-sec-2" class="outline-2">
188+
<h2 id="sec-2"><span class="section-number-2">2</span> JVM解释运行过程</h2>
189+
<div class="outline-text-2" id="text-2">
190+
<p>
191+
Java语言的运行,是将Java文件编译成class文件,然后加载到虚拟机上运行的。在不考虑JIT(<a href="https://www.ibm.com/developerworks/cn/java/j-lo-just-in-time/">Java及时编译</a>) 的情况下,jvm是解释执行的,而且是基于栈实现的运算。
192+
这句话是什么意思呢?比如我们常见的一行代码:
193+
</p>
194+
<div class="org-src-container">
195+
196+
<pre class="src src-java">int a = 2 + 3;
197+
</pre>
198+
</div>
199+
<p>
200+
这是一个常见的赋值表达式,含义是声明一个变量a,将2+2的值赋值给变量a。其中2+3是生活中常见的数学表达式,我们称这种形式的表达式为中缀表达式。而经过javac编译后
201+
将形成后缀表达式的形式:2 3 + 的形式。Java的解释执行器在读入该行代码的时候,会将2从内存加载到栈里面;然后读取3加载到栈里面,然后读取到+运算符,就会将+运算符需要
202+
的两个参数,也就是栈里面的2和3弹出来,然后送给CPU做加法运算。CPU运算完成后,将运算结果4压入栈中。然后通过istore命令将4的值存到变量a指向的内存地址中。
203+
关于前缀表达式,中缀表达和后缀表达式三种表达式求值的运算逻辑可参考<a href="http://blog.csdn.net/antineutrino/article/details/6763722/">csdn博客</a> 。
204+
</p>
205+
</div>
206+
</div>
207+
208+
<div id="outline-container-sec-3" class="outline-2">
209+
<h2 id="sec-3"><span class="section-number-2">3</span> class文件结构说明</h2>
210+
<div class="outline-text-2" id="text-3">
211+
<p>
212+
源文件T.java
213+
</p>
214+
<div class="org-src-container">
215+
216+
<pre class="src src-java">public class T {
217+
public void test() {
218+
int a=1,b=1,c=1,d=2;
219+
System.out.println(a + "s" + b + c + d);
220+
}
221+
}
222+
</pre>
223+
</div>
224+
<p>
225+
我们通过javac T.java 命令编译,然后再使用javap -verbose T命令查看编译后的class文件结构
226+
</p>
227+
<hr />
228+
<p>
229+
编译生成的T.class文件结构:
230+
</p>
231+
<div class="org-src-container">
232+
233+
<pre class="src src-java">public void test();
234+
descriptor: ()V
235+
flags: ACC_PUBLIC
236+
Code:
237+
stack=3, locals=5, args_size=1
238+
0: iconst_1
239+
1: istore_1
240+
2: iconst_1
241+
3: istore_2
242+
4: iconst_1
243+
5: istore_3
244+
6: iconst_2
245+
7: istore 4
246+
9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
247+
12: new #3 // class java/lang/StringBuilder
248+
15: dup
249+
16: invokespecial #4 // Method java/lang/StringBuilder."&lt;init&gt;":()V
250+
19: iload_1
251+
20: invokevirtual #5 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
252+
23: ldc #6 // String s
253+
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
254+
28: iload_2
255+
29: invokevirtual #5 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
256+
32: iload_3
257+
33: invokevirtual #5 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
258+
36: iload 4
259+
38: invokevirtual #5 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
260+
41: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
261+
44: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
262+
47: return
263+
LineNumberTable:
264+
line 3: 0
265+
line 4: 9
266+
line 5: 47
267+
</pre>
268+
</div>
269+
<p>
270+
上面的源码只截取了test方法的编译结果。我们重点关注Code部分。
271+
</p>
272+
</div>
273+
<div id="outline-container-sec-3-1" class="outline-3">
274+
<h3 id="sec-3-1"><span class="section-number-3">3.1</span> stack</h3>
275+
<div class="outline-text-3" id="text-3-1">
276+
<p>
277+
我们首先关注的是stack=3,这句话的含义是test方法在执行的过程中需要的最大操作数栈深度为3。根据我们上一节解释的,jvm是基于栈进行解释执行的。
278+
我们按照编译出来的jvm字节码一行一行的模拟jvm的运行过程
279+
</p>
280+
<div class="org-src-container">
281+
282+
<pre class="src src-java"> 0: iconst_1 :将int1压入栈
283+
1: istore_1 :将栈顶的1弹出赋值给变量a
284+
2: iconst_1 :将int1压入栈
285+
3: istore_2 :将栈顶的1弹出赋值给变量b
286+
4: iconst_1 :
287+
5: istore_3 :
288+
6: iconst_2 :将int2压入栈
289+
7: istore 4 :将栈顶的2弹出赋值给变量d
290+
9: getstatic #2 :获取PrintStream对象
291+
12: new #3 :新建StringBuilder对象,并将对象地址值压入栈,stack=1
292+
15: dup :复制栈顶值,并压入栈,stack=2
293+
16: invokespecial #4 :执行SB对象的初始化方法
294+
19: iload_1 :将变量a的值压入栈,stack=3
295+
20: invokevirtual #5 :执行append方法,依次弹出栈顶的a和sb,stack=1,执行完成append方法后,将sb对象压入栈,stack=2。
296+
23: ldc #6 :将字符s压入栈,stack=3
297+
25: invokevirtual #7 :执行append方法,将s和sb弹出栈,stack=1,执行完成append方法,将sb压入栈,stack=2。
298+
28: iload_2 :同19
299+
29: invokevirtual #5 :同20
300+
32: iload_3 :同19
301+
33: invokevirtual #5 :同20
302+
36: iload 4 :同19
303+
38: invokevirtual #5 :同20
304+
41: invokevirtual #8 :执行sb的toString方法,并将返回的字符串压入栈,stack=2
305+
44: invokevirtual #9 :将栈顶的字符串弹出,执行println方法,stack=1
306+
47: return :方法返回,无须返回值
307+
</pre>
308+
</div>
309+
<p>
310+
观察整个执行过程后,可以得出,test在执行的过程中,使用到的最大操作数栈的深度为3。
311+
</p>
312+
</div>
313+
</div>
314+
<div id="outline-container-sec-3-2" class="outline-3">
315+
<h3 id="sec-3-2"><span class="section-number-3">3.2</span> locals</h3>
316+
<div class="outline-text-3" id="text-3-2">
317+
<p>
318+
locals是本地变量的数量。本例中,共需要储存三个1,一个2和一个this指针,所以本地变量表中需要5个slot储存变量。主意long和double是64位的,所以需要两个slot存储。但本例中,
319+
5个变量都是32位的,不需要扩展slot。
320+
</p>
321+
</div>
322+
</div>
323+
<div id="outline-container-sec-3-3" class="outline-3">
324+
<h3 id="sec-3-3"><span class="section-number-3">3.3</span> arg_size</h3>
325+
<div class="outline-text-3" id="text-3-3">
326+
<p>
327+
arg_size是方法参数的个数,因为该方法是实例方法,所以会默认传入this指针作为参数,所以需要占用一个本地变量表的位置和一个参数位。如果将test方法改为static的,则不需要传入
328+
this指针,就不会占用了,locals将变成4,arg_size变成0。读者可自行实验验证。
329+
</p>
330+
</div>
331+
</div>
332+
</div>
333+
334+
<div id="outline-container-sec-4" class="outline-2">
335+
<h2 id="sec-4"><span class="section-number-2">4</span> 结论</h2>
336+
<div class="outline-text-2" id="text-4">
337+
<p>
338+
-javac编译的时候,会把我们常见的中缀表达式翻译成jvm使用的后缀表达式
339+
-jvm是基于栈进行解释执行的
340+
-class文件中stack是方法执行过程中用到的最大操作数栈深度
341+
-class文件中locals是本地变量表中变量需要的slot的个数
342+
-class文件中arg\_size是方法的参数个数
343+
-static方法不需要传入this指针,但非static方法默认会传入this指针。this要占用本地变量表中slot的个数和方法参数的个数
344+
</p>
345+
</div>
346+
</div>
347+
</div>
348+
<div id="postamble" class="status">
349+
<p class="author">Author: 王月阳</p>
350+
<p class="email">Email: <a href="mailto:[email protected]">[email protected]</a></p>
351+
<p class="date">Created: 2017-09-17 周日 11:05</p>
352+
<p class="creator"><a href="http://www.gnu.org/software/emacs/">Emacs</a> 24.5.1 (<a href="http://orgmode.org">Org</a> mode 8.2.10)</p>
353+
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
354+
</div>
355+
</body>
356+
</html>

0 commit comments

Comments
 (0)