forked from zyb0408/zyb0408.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2018-11-14-Java虚拟机.html
1406 lines (851 loc) · 78.1 KB
/
2018-11-14-Java虚拟机.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html class="theme-next pisces use-motion" lang="zh-Hans">
<head><meta name="generator" content="Hexo 3.8.0">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">
<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
<link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">
<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">
<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">
<meta name="keywords" content="Computer Siencise, OpenCV, TensorFlow">
<meta name="description" content="JAVA工作方式源程序(myProgram.java) – &gt; 编译(javac myProgram.java) -&gt; JAVA字节码(myProgram.class) -&gt;运行(java myProgram) JAVA的程序结构源文件&gt;类&gt;方法&gt;语句(source file &gt; class &gt; method &gt; statement) JDK、">
<meta name="keywords" content="TensorFlow OpenCV">
<meta property="og:type" content="article">
<meta property="og:title" content="Java虚拟机">
<meta property="og:url" content="https://zyb0408.github.io/2018-11-14-Java虚拟机.html">
<meta property="og:site_name" content="小蜜蜂">
<meta property="og:description" content="JAVA工作方式源程序(myProgram.java) – &gt; 编译(javac myProgram.java) -&gt; JAVA字节码(myProgram.class) -&gt;运行(java myProgram) JAVA的程序结构源文件&gt;类&gt;方法&gt;语句(source file &gt; class &gt; method &gt; statement) JDK、">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/JVM内存.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/JVM.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/JAVM内存2.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/内存分区.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/java堆.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/对象.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/栈帧.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/对内润.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/类加载过程2.png">
<meta property="og:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/类加载过程.png">
<meta property="og:updated_time" content="2018-11-14T04:17:02.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java虚拟机">
<meta name="twitter:description" content="JAVA工作方式源程序(myProgram.java) – &gt; 编译(javac myProgram.java) -&gt; JAVA字节码(myProgram.class) -&gt;运行(java myProgram) JAVA的程序结构源文件&gt;类&gt;方法&gt;语句(source file &gt; class &gt; method &gt; statement) JDK、">
<meta name="twitter:image" content="http://www.dhu021.top/wp-content/uploads/2018/11/JVM内存.png">
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '/',
scheme: 'Pisces',
version: '5.1.4',
sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":true,"onmobile":false},
fancybox: true,
tabs: true,
motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
duoshuo: {
userId: '0',
author: '博主'
},
algolia: {
applicationID: '',
apiKey: '',
indexName: '',
hits: {"per_page":10},
labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
}
};
</script>
<link rel="canonical" href="https://zyb0408.github.io/2018-11-14-Java虚拟机.html">
<title>Java虚拟机 | 小蜜蜂</title>
</head>
<body itemscope="" itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container sidebar-position-left page-post-detail">
<div class="headband"></div>
<header id="header" class="header" itemscope="" itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-wrapper">
<div class="site-meta custom-logo">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">小蜜蜂</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle">Don't Hack Me</p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br>
首页
</a>
</li>
<li class="menu-item menu-item-about">
<a href="/about/" rel="section">
<i class="menu-item-icon fa fa-fw fa-user"></i> <br>
关于
</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags/" rel="section">
<i class="menu-item-icon fa fa-fw fa-tags"></i> <br>
标签
</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/categories/" rel="section">
<i class="menu-item-icon fa fa-fw fa-th"></i> <br>
分类
</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives/" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
归档
</a>
</li>
<li class="menu-item menu-item-search">
<a href="javascript:;" class="popup-trigger">
<i class="menu-item-icon fa fa-search fa-fw"></i> <br>
搜索
</a>
</li>
</ul>
<div class="site-search">
<div class="popup search-popup local-search-popup">
<div class="local-search-header clearfix">
<span class="search-icon">
<i class="fa fa-search"></i>
</span>
<span class="popup-btn-close">
<i class="fa fa-times-circle"></i>
</span>
<div class="local-search-input-wrapper">
<input autocomplete="off" placeholder="搜索..." spellcheck="false" type="text" id="local-search-input">
</div>
</div>
<div id="local-search-result"></div>
</div>
</div>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<div id="posts" class="posts-expand">
<article class="post post-type-normal" itemscope="" itemtype="http://schema.org/Article">
<div class="post-block">
<link itemprop="mainEntityOfPage" href="https://zyb0408.github.io/2018-11-14-Java虚拟机.html">
<span hidden itemprop="author" itemscope="" itemtype="http://schema.org/Person">
<meta itemprop="name" content="小蜜蜂">
<meta itemprop="description" content="">
<meta itemprop="image" content="/images/favicon-32x32-next.png">
</span>
<span hidden itemprop="publisher" itemscope="" itemtype="http://schema.org/Organization">
<meta itemprop="name" content="小蜜蜂">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">Java虚拟机</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建于" itemprop="dateCreated datePublished" datetime="2018-11-14T12:17:02+08:00">
2018-11-14
</time>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-calendar-check-o"></i>
</span>
<span class="post-meta-item-text">更新于:</span>
<time title="更新于" itemprop="dateModified" datetime="2018-11-14T12:17:02+08:00">
2018-11-14
</time>
</span>
<span class="post-category">
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope="" itemtype="http://schema.org/Thing">
<a href="/categories/Java/" itemprop="url" rel="index">
<span itemprop="name">Java</span>
</a>
</span>
</span>
<span class="post-meta-divider">|</span>
<span class="page-pv"><i class="fa fa-file-o"></i>
<span class="busuanzi-value" id="busuanzi_value_page_pv"></span>
</span>
<div class="post-wordcount">
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-file-word-o"></i>
</span>
<span class="post-meta-item-text">字数统计:</span>
<span title="字数统计">
8.1k
</span>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-clock-o"></i>
</span>
<span class="post-meta-item-text">阅读时长 ≈</span>
<span title="阅读时长">
29
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<div>
<div>
<div style="text-align:center;color: #636363;font-size:14px;letter-spacing: 10px">���Ľ�����<i class="fa fa-bell"></i>��л�����Ķ�</div>
</div>
</div>
<h2 id="JAVA工作方式"><a href="#JAVA工作方式" class="headerlink" title="JAVA工作方式"></a>JAVA工作方式</h2><p>源程序(myProgram.java) – > 编译(javac myProgram.java) -> JAVA字节码(myProgram.class) ->运行(java myProgram)</p>
<h2 id="JAVA的程序结构"><a href="#JAVA的程序结构" class="headerlink" title="JAVA的程序结构"></a><strong>JAVA的程序结构</strong></h2><p>源文件>类>方法>语句(source file > class > method > statement)</p>
<h2 id="JDK、JRE、JVM的区别"><a href="#JDK、JRE、JVM的区别" class="headerlink" title="JDK、JRE、JVM的区别"></a><strong>JDK、JRE、JVM的区别</strong></h2><ul>
<li>JVM(Java Virtual Machine):JAVA虚拟机</li>
<li>JDK(Java Developer’s Kit):Java开发工具包</li>
<li>JRE(Java runtime environment):Java 运行环境</li>
</ul>
<h2 id="JVM主要包括四个部分"><a href="#JVM主要包括四个部分" class="headerlink" title="JVM主要包括四个部分"></a>JVM主要包括四个部分</h2><p><strong>1.类加载器(ClassLoader)</strong>:在JVM启动时或者在类运行时将需要的class加载到JVM中。 <strong>2.执行引擎:</strong>负责执行class文件中包含的字节码指令 <strong>3.内存区(也叫运行时数据区):</strong>是在JVM运行的时候操作所分配的内存区。运行时内存区主要可以划分为5个区域,如图: <img src="http://www.dhu021.top/wp-content/uploads/2018/11/JVM内存.png" alt=""></p>
<ul>
<li><p>方法区(Method Area):用于存储类结构信息的地方,包括常量池、静态变量、构造函数等。虽然JVM规范把方法区描述为堆的一个逻辑部分, 但它却有个别名non-heap(非堆),所以大家不要搞混淆了。方法区还包含一个运行时常量池。</p>
</li>
<li><p>java堆(Heap):存储java实例或者对象的地方。这块是GC的主要区域(后面解释)。从存储的内容我们可以很容易知道,方法区和堆是被所有java线程共享的。</p>
</li>
<li><p>java栈(Stack):java栈总是和线程关联在一起,每当创建一个线程时,JVM就会为这个线程创建一个对应的java栈。在这个java栈中又会包含多个栈帧,每运行一个方法就创建一个栈帧,用于存储局部变量表、操作栈、方法返回值等。每一个方法从调用直至执行完成的过程,就对应一个栈帧在java栈中入栈到出栈的过程。所以java栈是现成私有的。</p>
</li>
<li><p>程序计数器(PC Register):用于保存当前线程执行的内存地址。由于JVM程序是多线程执行的(线程轮流切换),所以为了保证线程切换回来后,还能恢复到原先状态,就需要一个独立的计数器,记录之前中断的地方,可见程序计数器也是线程私有的。</p>
</li>
<li>本地方法栈(Native Method Stack):和java栈的作用差不多,只不过是为JVM使用到的native方法服务的</li>
</ul>
<p><strong>4.本地方法接口:</strong>主要是调用C或C++实现的本地方法及返回结果。 JVM在整个JDK中处于最底层,负责与操作系统的交互,用来屏蔽操作系统环境,提供一个王正的Java运行环境,因此也称为虚拟计算机。操作系统装入JVM是通过JDK中的java.exe来实现,主要以下几步: 1.创建jvm装载环境和配置 2.装载jvm.dll 3.初始化jvm.dll 4.调用JNIEnv实例装载并处理class类 5.运行java程序</p>
<h2 id="JVM初识及工作原理"><a href="#JVM初识及工作原理" class="headerlink" title="JVM初识及工作原理"></a><strong>JVM初识及工作原理</strong></h2><p><img src="http://www.dhu021.top/wp-content/uploads/2018/11/JVM.png" alt=""> 1)类加载子系统负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中可能还会存放运行时常量池信息,包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)。 2)java堆在虚拟机启动的时候建立,它是java程序最主要的内存工作区域。几乎所有的java对象实例都存放在java堆中。堆空间是所有线程共享的,这是一块与java应用密切相关的内存空间。 3)java的NIO库允许java程序使用直接内存。直接内存是在java堆外的、直接向系统申请的内存空间。通常访问直接内存的速度会优于java堆。因此出于性能的考虑,读写频繁的场合可能会考虑使用直接内存。由于直接内存在java堆外,因此它的大小不会直接受限于Xmx指定的最大堆大小,但是系统内存是有限的,java堆和直接内存的总和依然受限于操作系统能给出的最大内存。 4)垃圾回收系统是java虚拟机的重要组成部分,垃圾回收器可以对方法区、java堆和直接内存进行回收。其中,java堆是垃圾收集器的工作重点。和C/C++不同,java中所有的对象空间释放都是隐式的,也就是说,java中没有类似free()或者delete()这样的函数释放指定的内存区域。对于不再使用的垃圾对象,垃圾回收系统会在后台默默工作,默默查找、标识并释放垃圾对象,完成包括java堆、方法区和直接内存中的全自动化管理。 5)每一个java虚拟机线程都有一个私有的java栈,一个线程的java栈在线程创建的时候被创建,java栈中保存着帧信息,java栈中保存着局部变量、方法参数,同时和java方法的调用、返回密切相关。 6)本地方法栈和java栈非常类似,最大的不同在于java栈用于方法的调用,而本地方法栈则用于本地方法的调用,作为对java虚拟机的重要扩展,java虚拟机允许java直接调用本地方法(通常使用C编写) 7)PC(Program Counter)寄存器也是每一个线程私有的空间,java虚拟机会为每一个java线程创建PC寄存器。在任意时刻,一个java线程总是在执行一个方法,这个正在被执行的方法称为当前方法。如果当前方法不是本地方法,PC寄存器就会指向当前正在被执行的指令。如果当前方法是本地方法,那么PC寄存器的值就是undefined 8)执行引擎是java虚拟机的最核心组件之一,它负责执行虚拟机的字节码,现代虚拟机为了提高执行效率,会使用即时编译技术将方法编译成机器码后再执行。 <img src="http://www.dhu021.top/wp-content/uploads/2018/11/JAVM内存2.png" alt=""></p>
<h2 id="java堆"><a href="#java堆" class="headerlink" title="java堆"></a><strong>java堆</strong></h2><p>java堆是和应用程序关系最为密切的内存空间,几乎所有的对象都存放在堆上。并且java堆是完全自动化管理的,通过垃圾回收机制,垃圾对象会被自动清理,而不需要显示的释放。 根据java回收机制的不同,java堆有可能拥有不同的结构。最为常见的一种构成是将整个java堆分为新生代和老年代。其中新生代存放新生对象或者年龄不大的对象,老年代则存放老年对象。新生代有可能分为eden区、s0区、s1区,s0区和s1区也被称为from和to区,他们是两块大小相同、可以互换角色的内存空间。 如下图:显示了一个堆空间的一般结构: <img src="http://www.dhu021.top/wp-content/uploads/2018/11/内存分区.png" alt=""> <img src="http://www.dhu021.top/wp-content/uploads/2018/11/java堆.png" alt=""> 在绝大多数情况下,对象首先分配在eden区,在一次新生代回收之后,如果对象还存活,则进入s0或者s1,每经过一次新生代回收,对象如果存活,它的年龄就会加1。当对象的年龄达到一定条件后,就会被认为是老年对象,从而进入老年代。</p>
<pre><code>public class SimpleHeap {
private int id;
public SimpleHeap(int id){
this.id = id;
}
public void show(){
System.out.println("My id is "+id);
}
public static void main(String[] args) {
SimpleHeap s1 = new SimpleHeap(1);
SimpleHeap s2 = new SimpleHeap(2);
s1.show();
s2.show();
}
}
</code></pre><p>该代码声明了一个类,并在main函数中创建了两个SimpleHeap实例。此时,各对象和局部变量的存放情况如图: SimpleHeap实例本身分配在堆中,描述SimpleHeap类的信息存放在方法区,main函数中的s1 s2局部变量存放在java栈上,并指向堆中两个实例。 <img src="http://www.dhu021.top/wp-content/uploads/2018/11/对象.png" alt=""></p>
<h2 id="java栈"><a href="#java栈" class="headerlink" title="java栈"></a><strong>java栈</strong></h2><p>java栈是一块线程私有的内存空间。如果说,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关。线程执行的基本行为是函数调用,每次函数调用的数据都是通过java栈传递的。 java栈与数据结构上的栈有着类似的含义,它是一块先进后出的数据结构,只支持出栈和进栈两种操作,在java栈中保存的主要内容为栈帧。每一次函数调用,都会有一个对应的栈帧被压入java栈,每一个函数调用结束,都会有一个栈帧被弹出java栈。如下图:栈帧和函数调用。函数1对应栈帧1,函数2对应栈帧2,依次类推。函数1中调用函数2,函数2中调用函数3,函数3调用函数4.当函数1被调用时,栈帧1入栈,当函数2调用时,栈帧2入栈,当函数3被调用时,栈帧3入栈,当函数4被调用时,栈帧4入栈。当前正在执行的函数所对应的帧就是当前帧(位于栈顶),它保存着当前函数的局部变量、中间计算结果等数据。 当函数返回时,栈帧从java栈中被弹出,java方法区有两种返回函数的方式,一种是正常的函数返回,使用return指令,另一种是抛出异常。不管使用哪种方式,都会导致栈帧被弹出。 在一个栈帧中,至少包含局部变量表、操作数栈和帧数据区几个部分。 <img src="http://www.dhu021.top/wp-content/uploads/2018/11/栈帧.png" alt=""> 由于每次函数调用都会产生对应的栈帧,从而占用一定的栈空间,因此,如果栈空间不足,那么函数调用自然无法继续进行下去。当请求的栈深度大于最大可用栈深度时,系统会抛出StackOverflowError栈溢出错误。 使用递归,由于递归没有出口,这段代码可能会抛出栈溢出错误,在抛出栈溢出错误时,打印最大的调用深度。 使用参数-Xss128K执行下面代码(在eclipse中右键选择Run As–>run Configurations….设置Vm arguments) 发生了栈溢出错误,通过增大-Xss的值,可以获得更深的层次调用,尝试使用参数-Xss256K执行下述代码</p>
<pre><code>public class TestStackDeep {
private static int count =0;
public static void recursion(){
count ++;
recursion();
}
public static void main(String[] args) {
try{
recursion();
}catch(Throwable e){
System.out.println("deep of calling ="+count);
e.printStackTrace();
}
}
}
</code></pre><p>函数嵌套调用的层次在很大程度上由栈的大小决定,栈越大,函数支持的嵌套调用次数就越多。</p>
<h3 id="栈帧组成之局部变量表"><a href="#栈帧组成之局部变量表" class="headerlink" title="栈帧组成之局部变量表"></a><strong>栈帧组成之局部变量表</strong></h3><p>局部变量表是栈帧的重要组成部分之一。它用于保存函数的参数以及局部变量,局部变量表中的变量只在当前函数调用中有效,当函数调用结束,随着函数栈帧的弹出销毁,局部变量表也会随之销毁。 由于局部变量表在栈帧之中,因此,如果函数的参数和局部变量很多,会使得局部变量表膨胀,从而每一次函数调用就会占用更多的栈空间,最终导致函数的嵌套调用次数减少。 一个recursion函数含有3个参数和10个局部变量,因此,其局部变量表含有13个变量,而第二个recursion函数不再含有任何参数和局部变量,当这两个函数被嵌套调用时,第二个recursion函数可以拥有更深的调用层次。</p>
<pre><code>public class TestStackDeep2 {
private static int count = 0;
public static void recursion(long a,long b,long c){
long e=1,f=2,g=3,h=4,i=5,k=6,q=7,x=8,y=9,z=10;
count ++;
recursion(a,b,c);
}
public static void recursion(){
count++;
recursion();
}
public static void main(String[] args) {
try{
recursion(0L,0L,0L);
//recursion();
}catch(Throwable e){
System.out.println("deep of calling = "+count);
e.printStackTrace();
}
}
}
</code></pre><p>使用参数-Xss128K执行上述代码中的第一个带参recursion(long a,long b,long c)函数。可以知道输出调用次数后抛出异常。 使用虚拟机参数-Xss128K执行上述代码中第二个不带参数的recursion()函数(当然需要把第一个函数注释掉)。可以看出,在相同的栈容量下,局部变量少的函数可以支持更深的函数调用。即输出次数比上次增加。 第一个带参recursion(long a,long b,long c)的最大局部变量表的大小为26个字,因为该函数包含总共13个参数和局部变量,且都为long型,long和double在局部变量表中需要占用<strong>2个字</strong>,其他如int short byte 对象引用等占用一个字。 <strong>说明</strong>:字(word)指的是计算机内存中占据一个单独的内存单元编号的一组二进制串,一般32位计算机上一个字为4个字节长度。 栈帧中局部变量表中的槽位是可以重用的,如果一个局部变量过了其作用域,那么在其作用域之后申明的新的局部变量就很有可能会复用过期局部变量的槽位,从而达到节省资源的目的。</p>
<h2 id="垃圾回收"><a href="#垃圾回收" class="headerlink" title="垃圾回收"></a>垃圾回收</h2><p><strong>目前为止,jvm**</strong>已经发展处三种比较成熟的垃圾收集算法:1.<strong><strong>标记-</strong></strong>清除算法;2.<strong><strong>复制算法;3.</strong></strong>标记-<strong><strong>整理算法;4.</strong></strong>分代收集算法**</p>
<h3 id="1-标记-清除算法"><a href="#1-标记-清除算法" class="headerlink" title="1.**标记-**清除算法"></a><strong>1.**</strong>标记-<strong>**清除算法</strong></h3><p>这种垃圾回收一次回收分为两个阶段:标记、清除。首先标记所有需要回收的对象,在标记完成后回收所有被标记的对象。这种回收算法会产生大量不连续的内存碎片,当要频繁分配一个大对象时,jvm在新生代中找不到足够大的连续的内存块,会导致jvm频繁进行内存回收(目前有机制,对大对象,直接分配到老年代中)</p>
<h3 id="2-复制算法"><a href="#2-复制算法" class="headerlink" title="2.**复制算法**"></a><strong>2.**</strong>复制算法**</h3><p>这种算法会将内存划分为两个相等的块,每次只使用其中一块。当这块内存不够使用时,就将还存活的对象复制到另一块内存中,然后把这块内存一次清理掉。这样做的效率比较高,也避免了内存碎片。但是这样内存的可使用空间减半,是个不小的损失。</p>
<h3 id="3-标记-整理算法"><a href="#3-标记-整理算法" class="headerlink" title="3.**标记-**整理算法"></a><strong>3.**</strong>标记-<strong>**整理算法</strong></h3><p>这是标记-清除算法的升级版。在完成标记阶段后,不是直接对可回收对象进行清理,而是让存活对象向着一端移动,然后清理掉边界以外的内存</p>
<h3 id="4-分代收集算法"><a href="#4-分代收集算法" class="headerlink" title="4.**分代收集算法**"></a><strong>4.**</strong>分代收集算法**</h3><p>当前商业虚拟机都采用这种算法。首先根据对象存活周期的不同将内存分为几块即新生代、老年代,然后根据不同年代的特点,采用不同的收集算法。在新生代中,每次垃圾收集时都有大量对象死去,只有少量存活,所以选择了复制算法。而老年代中因为对象存活率比较高,所以采用标记-整理算法(或者标记-清除算法)</p>
<h3 id="GC-的执行机制"><a href="#GC-的执行机制" class="headerlink" title="GC**的执行机制**"></a><strong>GC**</strong>的执行机制**</h3><p>由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。 <strong>Minor **</strong>GC<strong> 一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发MinorGC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。 </strong>Full GC** 对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比MinorGC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC: 1.年老代(Tenured)被写满 2.持久代(Perm)被写满 3.System.gc()被显示调用 4.上一次GC之后Heap的各域分配策略动态变化</p>
<h3 id="为什么要运用分代垃圾回收策略?"><a href="#为什么要运用分代垃圾回收策略?" class="headerlink" title="为什么要运用分代垃圾回收策略?"></a><strong>为什么要运用分代垃圾回收策略?</strong></h3><p>在java程序运行的过程中,会产生大量的对象,因每个对象所能承担的职责不同所具有的功能不同所以也有着不一样的生命周期,有的对象生命周期较长,比如Http请求中的Session对象,线程,Socket连接等;有的对象生命周期较短,比如String对象,由于其不变类的特性,有的在使用一次后即可回收。试想,在不进行对象存活时间区分的情况下,每次垃圾回收都是对整个堆空间进行回收,那么消耗的时间相对会很长,而且对于存活时间较长的对象进行的扫描工作等都是徒劳。因此就需要引入分治的思想,所谓分治的思想就是因地制宜,将对象进行代的划分,把不同生命周期的对象放在不同的代上使用不同的垃圾回收方式。 <img src="http://www.dhu021.top/wp-content/uploads/2018/11/对内润.png" alt=""> 通过一个简单示例,展示局部变量对垃圾回收的影响。<br><figure class="highlight cs"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">LocalvarGC</span> {</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">localvarGc1</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">byte</span>[] a = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">6</span>*<span class="number">1024</span>*<span class="number">1024</span>];<span class="comment">//6M</span></span><br><span class="line"> System.gc();</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">localvarGc2</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">byte</span>[] a = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">6</span>*<span class="number">1024</span>*<span class="number">1024</span>];</span><br><span class="line"> a = <span class="literal">null</span>;</span><br><span class="line"> System.gc();</span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">localvarGc3</span>(<span class="params"></span>)</span>{</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">byte</span>[] a = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">6</span>*<span class="number">1024</span>*<span class="number">1024</span>];</span><br><span class="line"> }</span><br><span class="line"> System.gc();</span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">localvarGc4</span>(<span class="params"></span>)</span>{</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">byte</span>[] a = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">6</span>*<span class="number">1024</span>*<span class="number">1024</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> c = <span class="number">10</span>;</span><br><span class="line"> System.gc();</span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">localvarGc5</span>(<span class="params"></span>)</span>{</span><br><span class="line"> localvarGc1();</span><br><span class="line"> System.gc();</span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span>(<span class="params">String[] args</span>)</span> {</span><br><span class="line"> LocalvarGC ins = <span class="keyword">new</span> LocalvarGC();</span><br><span class="line"> ins.localvarGc1();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>每一个localvarGcN()函数都分配了一块6M的堆内存,并使用局部变量引用这块空间。 在localvarGc1()中,在申请空间后,立即进行垃圾回收,很明显由于byte数组被变量a引用,因此无法回收这块空间。 在localvarGc2()中,在垃圾回收前,先将变量a置为null,使得byte数组失去强引用,故垃圾回收可以顺利回收byte数组。 在localvarGc3()中,在进行垃圾回收前,先使局部变量a失效,虽然变量a已经离开了作用域,但是变量a依然存在于局部变量表中,并且也指向这块byte数组,故byte数组依然无法被回收。 对于localvarGc4(),在垃圾回收之前,不仅使变量a失效,更是声明了变量c,使变量c复用了变量a的字,由于变量a此时被销毁,故垃圾回收器可以顺利回收数组byte 对于localvarGc5(),它首先调用了localvarGc1(),很明显,在localvarGc1()中并没有释放byte数组,但在localvarGc1()返回后,它的栈帧被销毁,自然也包含了栈帧中的所有局部变量,故byte数组失去了引用,在localvarGc5()的垃圾回收中被回收。 可以使用-XX:+printGC执行上述几个函数,在输出日志里,可以看到垃圾回收前后堆的大小,进而推断出byte数组是否被回收。 下面的输出是函数localvarGc4()的运行结果: [GC (System.gc())<strong> 7618K->624K</strong>(94208K), 0.0015613 secs] [Full GC (System.gc()) 624K->526K(94208K), 0.0070718 secs] 从日志中可以看出,堆空间从回收前的7618K变为回收后的624K,释放了>6M的空间,byte数组已经被回收释放。</p>
<h2 id="类加载过程"><a href="#类加载过程" class="headerlink" title="类加载过程"></a>类加载过程</h2><p>分三步,细化为五步。 <img src="http://www.dhu021.top/wp-content/uploads/2018/11/类加载过程2.png" alt=""> 类加载的五个过程:</p>
<ul>
<li><strong>加载</strong></li>
<li><strong>验证</strong></li>
<li><strong>准备</strong></li>
<li><strong>解析</strong></li>
<li><strong>初始化</strong></li>
</ul>
<p>类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading)七个阶段,其中验证、准备、解析三个部分统称链接。 <img src="http://www.dhu021.top/wp-content/uploads/2018/11/类加载过程.png" alt=""></p>
<h3 id="加载:完成三件事"><a href="#加载:完成三件事" class="headerlink" title="加载:完成三件事"></a><strong>加载</strong>:完成三件事</h3><ul>
<li>通过类的全限定名来获取定义此类的二进制字节流</li>
<li>将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构</li>
<li>在内存中生成一个代表这个类的<code>java.lang.Class</code>对象,作为方法区这个类的各种数据的访问入口。</li>
</ul>
<p>简单来说,加载指的是把class字节码文件从各个来源通过类加载器装载入内存中。 这里有两个重点: 1. 字节码来源。一般的加载来源包括从本地路径下编译生成的.class文件,从jar包中的.class文件,从远程网络,以及动态代理实时编译 2. 类加载器。一般包括启动类加载器,扩展类加载器,应用类加载器,以及用户的自定义类加载器。 注:为什么会有自定义类加载器? 一方面是由于java代码很容易被反编译,如果需要对自己的代码加密的话,可以对编译后的代码进行加密,然后再通过实现自己的自定义类加载器进行解密,最后再加载。 另一方面也有可能从非标准的来源加载代码,比如从网络来源,那就需要自己实现一个类加载器,从指定源进行加载。</p>
<h3 id="验证:四个阶段的检验动作"><a href="#验证:四个阶段的检验动作" class="headerlink" title="验证:四个阶段的检验动作"></a><strong>验证</strong>:四个阶段的检验动作</h3><ul>
<li>文件格式验证</li>
<li>元数据验证</li>
<li>字节码验证</li>
<li>符号引用验证</li>
</ul>
<p>验证是连接阶段的第一步,这一阶段目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全。 虚拟机规范对这个阶段的限制和指导非常笼统,仅仅说了一句如果验证到输入的字节流不符合Class文件的存储格式,就抛出一个java.lang.VerifyError异常或者其子类异常。具体应当检查哪些方面,如何检查,何时检查,都没有强制要求或明确说明,所以不同的虚拟机对验证的实现可能会有所不同,但大致上都会完场下面四个阶段的检验过程:文件格式验证、元数据验证、字节码验证和符号引用验证。</p>
<h4 id="1-文件格式验证"><a href="#1-文件格式验证" class="headerlink" title="1.文件格式验证"></a>1.文件格式验证</h4><p>第一阶段要验证字节流是否符合Class文件格式的规范否,并且能被当前版本的虚拟机处理。该验证阶段的主要目的是保证输入的字节流能正确的解析并存储于方法区之内,格式上符合描述一个Java类型的信息的要求。这阶段的验证是基于字节流进行的,经过这个就饿段的验证之后,字节流才会进入内存的方法区进行存储,所以后面三个验证阶段全部是基于方法区的存储结构进行的。</p>
<h4 id="2-元数据验证"><a href="#2-元数据验证" class="headerlink" title="2.元数据验证"></a>2.元数据验证</h4><p>第二阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言的规范要求,这个阶段可能包括的验证点如下:</p>
<ul>
<li>这个类是否有父类(除了java.lang.Object之外,所有的类应当有父类)</li>
<li>这个类的父类是否继承了不允许被继承的类(被final修饰)</li>
<li>如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法。</li>
<li>类中的字段、方法是否与父类产生了矛盾</li>
<li>。。。。。</li>
</ul>
<h4 id="3-字节码验证"><a href="#3-字节码验证" class="headerlink" title="3.字节码验证"></a>3.字节码验证</h4><p>第三个阶段是验证过程中最复杂的一个,其主要工作是进行数据流和控制流分析。第二阶段对元数据信息中的数据类型做完校验后,这阶段将对类的方法体进行校验分析。这阶段的任务是保证被校验类的方法在运行时不会做出危害虚拟机安全的行为,例如:</p>
<ul>
<li>保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作,例如不会出现类似这种情况:在操作栈中放置了一个int类型的数据,使用时却按long类型来加载入本地变量表中。</li>
<li>保证跳转指令不会跳转到方法体以外的字节码指令上。</li>
<li>保证方法体中的类型转换是有效的,例如可以把一个子类对象赋值给父类数据类型,这是安全的,反之不合法。</li>
<li>。。。。。。</li>
</ul>
<p>如果一个类的方法体的字节码没有通过字节码验证,那肯定是有问题的;如果一个方法体通过了字节码验证,也不能说明其一定就是安全的。即使字节码验证之中进行了大量的检查,也不能保证这一点。这里涉及了离散数学中一个很著名的问题“Halting Problem“:通俗一点的说法就是,通过程序去校验程序逻辑是无法做到绝对准确的–不能通过程序准确地检查出程序是否能在有限的时间之内结束运行。 为避免将过多时间消耗在字节码验证阶段,1.6之后给方法体的Code属性的属性表中增加了一项名为“StackMapTable”的属性,这项属性描述了方法体重所有的基本块开始时本地变量表和操作栈应有的状态,这可以将字节码验证的类型推导转变为类型检查从而节省一些时间。使用-XX:-UseSplitVerifier选项来关闭掉这项优化,或者使用参数-XX:+FailOverToOldVerifier要求在类型校验失败的时候瑞回到旧的类型推导方式进行校验(1.7之后不允许)。</p>
<h4 id="4-符号引用验证"><a href="#4-符号引用验证" class="headerlink" title="4.符号引用验证"></a>4.符号引用验证</h4><p>最后一个阶段的校验发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在连接的第三个阶段——解析阶段中发生。符号引用验证可以看做是对类自身以外的信息进行匹配性的校验,通常需要校验以下内容:</p>
<ul>
<li>符号引用中通过字符串描述的全限定名是否能找到对应的类。</li>
<li>在指定类中是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。</li>
<li>符号引用中的类、字段和方法的访问性(private、protected、public、default)是否可被当前类访问。</li>
<li>。。。。。。</li>
</ul>
<p>符号引用验证的目的是确保解析动作能正常执行,如果无法通过符号引用验证,将会抛出一个java.lang.IncompatibleClassChangeError异常的子类,如java.lang.IllegalAccessError、java.lang.NoSuchFieldError、java.lang.NoSuchMethodError等。 验证阶段对于虚拟机的类加载机制来说,是一个非常重要、但不一定是必要的阶段。如果所运行的全部代码都已经被反复使用和验证过,在实施阶段就可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,以锁单虚拟机类加载的时间。</p>
<h3 id="准备:为类变量(static)分配内存并设置类变量的初始值。"><a href="#准备:为类变量(static)分配内存并设置类变量的初始值。" class="headerlink" title="准备:为类变量(static)分配内存并设置类变量的初始值。"></a><strong>准备</strong>:为类变量(<code>static</code>)分配内存并设置类变量的初始值。</h3><p>准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。这个阶段中有两个容易产生混淆的知识点,首先是这时候进行内存分配的仅包括类变量(static 修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在java堆中。其次是这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量定义为: public static int value = 12; 那么变量value在准备阶段过后的初始值为0而不是12,因为这时候尚未开始执行任何java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器<clinit>()方法之中,所以把value赋值为12的动作将在初始化阶段才会被执行。 上面所说的“通常情况”下初始值是零值,那相对于一些特殊的情况,如果类字段的字段属性表中存在ConstantValue属性,那在准备阶段变量value就会被初始化为ConstantValue属性所指定的值,建设上面类变量value定义为: public static final int value = 123; 注意,实例变量并不在这个阶段分配内存。为类变量设置初始值并不是定义的值。比如<code>static int value = 123;</code>那么变量<code>value</code>在准备阶段过后初始值为<code>0</code>,而不是<code>123</code>。值<code>123</code>是在<code><clinit>()</code>方法中赋予。</clinit></p>
<h3 id="解析:将常量池内的符号引用替换为直接引用的过程。"><a href="#解析:将常量池内的符号引用替换为直接引用的过程。" class="headerlink" title="解析:将常量池内的符号引用替换为直接引用的过程。"></a><strong>解析</strong>:将常量池内的符号引用替换为直接引用的过程。</h3><p>解析的动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行。分别对应编译后常量池内的CONSTANT_Class_Info、CONSTANT_Fieldref_Info、CONSTANT_Methodef_Info、CONSTANT_InterfaceMethoder_Info四种常量类型。 1.类、接口的解析 2.字段解析 3.类方法解析 4.接口方法解析 两个重点: 1. <strong>符号引用</strong>。即一个字符串,但是这个字符串给出了一些能够唯一性识别一个方法,一个变量,一个类的相关信息。 2. <strong>直接引用</strong>。可以理解为一个内存地址,或者一个偏移量。比如<strong>类方法,类变量</strong>的直接引用是指向方法区的<strong>指针</strong>;而<strong>实例方法,实例变量</strong>的直接引用则是从实例的头指针开始算起到这个实例变量位置的<strong>偏移量。</strong> 举个例子来说,现在调用方法helloWorld(),这个方法的地址是1234567,那么helloWorld就是符号引用,1234567就是直接引用。 在解析阶段,虚拟机会把所有的类名,方法名,字段名这些符号引用替换为具体的内存地址或偏移量,也就是直接引用。</p>
<h3 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a><strong>初始化</strong></h3><p>按照<code>static</code>块和<code>static</code>变量在文件中的出现顺序,合并到<code><clinit>()</code>方法中。实例变量由<code><init>()</code>函数赋值。 将一个类中所有被static关键字标识的代码统一执行一遍,如果执行的是静态变量,那么就会使用用户指定的值覆盖之前在准备阶段设置的初始值;如果执行的是static代码块,那么在初始化阶段,JVM就会执行static代码块中定义的所有操作。 所有类变量初始化语句和静态代码块都会在编译时被前端编译器放在收集器里头,存放到一个特殊的方法中,这个方法就是<clinit>方法,即类/接口初始化方法。该方法的作用就是初始化一个中的变量,使用用户指定的值覆盖之前在准备阶段里设定的初始值。任何invoke之类的字节码都无法调用<clinit>方法,因为该方法只能在类加载的过程中由JVM调用。 如果父类还没有被初始化,那么优先对父类初始化,但在<clinit>方法内部不会显示调用父类的<clinit>方法,由JVM负责保证一个类的<clinit>方法执行之前,它的父类<clinit>方法已经被执行。 JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待,只有在活动线程执行完对类的初始化操作之后,才会通知正在等待的其他线程。 参考: <a href="http://www.importnew.com/23035.html" target="_blank" rel="noopener">http://www.importnew.com/23035.html</a> <a href="https://www.cnblogs.com/BRE49/p/java-1.html" target="_blank" rel="noopener">https://www.cnblogs.com/BRE49/p/java-1.html</a> <a href="https://www.cnblogs.com/cherish010/p/8341611.html" target="_blank" rel="noopener">https://www.cnblogs.com/cherish010/p/8341611.html</a> <a href="https://www.cnblogs.com/fengbs/p/7082262.html" target="_blank" rel="noopener">https://www.cnblogs.com/fengbs/p/7082262.html</a> <a href="https://www.cnblogs.com/xiaoxian1369/p/5498817.html" target="_blank" rel="noopener">https://www.cnblogs.com/xiaoxian1369/p/5498817.html</a> <a href="http://www.darylliu.top/2018/01/31/144/" target="_blank" rel="noopener">http://www.darylliu.top/2018/01/31/144/</a></clinit></clinit></clinit></clinit></clinit></clinit></p>
</div>
<div>
<ul class="post-copyright">
<li class="post-copyright-author">
<strong>本文作者:</strong>
小蜜蜂
</li>
<li class="post-copyright-link">
<strong>本文链接:</strong>
<a href="https://zyb0408.github.io/2018-11-14-Java虚拟机.html" title="Java虚拟机">https://zyb0408.github.io/2018-11-14-Java虚拟机.html</a>
</li>
<li class="post-copyright-license">
<strong>版权声明: </strong>
本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/3.0/" rel="external nofollow" target="_blank">CC BY-NC-SA 3.0</a> 许可协议。转载请注明出处!
</li>
</ul>
</div>
<footer class="post-footer">
<div class="post-nav">
<div class="post-nav-next post-nav-item">
<a href="/2018-11-12-matplotlib使用.html" rel="next" title="matplotlib使用">
<i class="fa fa-chevron-left"></i> matplotlib使用
</a>
</div>
<span class="post-nav-divider"></span>
<div class="post-nav-prev post-nav-item">
<a href="/2018-11-14-Linux知识点.html" rel="prev" title="Linux知识点">
Linux知识点 <i class="fa fa-chevron-right"></i>
</a>
</div>
</div>
</footer>
</div>
</article>
<div class="post-spread">
</div>
</div>
</div>
</div>
<div class="sidebar-toggle">
<div class="sidebar-toggle-line-wrap">
<span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
<span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
<span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
</div>
</div>
<aside id="sidebar" class="sidebar">
<div class="sidebar-inner">
<ul class="sidebar-nav motion-element">
<li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
文章目录
</li>
<li class="sidebar-nav-overview" data-target="site-overview-wrap">
站点概览
</li>
</ul>
<section class="site-overview-wrap sidebar-panel">
<div class="site-overview">
<div class="site-author motion-element" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
<img class="site-author-image" itemprop="image" src="/images/favicon-32x32-next.png" alt="小蜜蜂">
<p class="site-author-name" itemprop="name">小蜜蜂</p>
<p class="site-description motion-element" itemprop="description">小蜜蜂学计算机</p>
</div>
<nav class="site-state motion-element">
<div class="site-state-item site-state-posts">
<a href="/archives/">
<span class="site-state-item-count">52</span>
<span class="site-state-item-name">日志</span>
</a>
</div>
<div class="site-state-item site-state-categories">
<a href="/categories/index.html">
<span class="site-state-item-count">18</span>
<span class="site-state-item-name">分类</span>
</a>
</div>
<div class="site-state-item site-state-tags">
<a href="/tags/index.html">
<span class="site-state-item-count">22</span>
<span class="site-state-item-name">标签</span>
</a>
</div>
</nav>
<div class="links-of-author motion-element">
<span class="links-of-author-item">
<a href="https://github.com/zyb0408" target="_blank" title="GitHub">
<i class="fa fa-fw fa-github"></i>GitHub</a>
</span>
</div>
<div class="links-of-blogroll motion-element links-of-blogroll-block">
<div class="links-of-blogroll-title">
<i class="fa fa-fw fa-link"></i>
Links
</div>
<ul class="links-of-blogroll-list">
<li class="links-of-blogroll-item">
<a href="https://dhupxd.github.io" title="学姐" target="_blank">学姐</a>
</li>
<li class="links-of-blogroll-item">
<a href="https://ztt001.github.io" title="学妹" target="_blank">学妹</a>
</li>
</ul>
</div>
</div>
</section>
<!--noindex-->
<section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
<div class="post-toc">
<div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#JAVA工作方式"><span class="nav-number">1.</span> <span class="nav-text">JAVA工作方式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JAVA的程序结构"><span class="nav-number">2.</span> <span class="nav-text">JAVA的程序结构</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JDK、JRE、JVM的区别"><span class="nav-number">3.</span> <span class="nav-text">JDK、JRE、JVM的区别</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JVM主要包括四个部分"><span class="nav-number">4.</span> <span class="nav-text">JVM主要包括四个部分</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JVM初识及工作原理"><span class="nav-number">5.</span> <span class="nav-text">JVM初识及工作原理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#java堆"><span class="nav-number">6.</span> <span class="nav-text">java堆</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#java栈"><span class="nav-number">7.</span> <span class="nav-text">java栈</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#栈帧组成之局部变量表"><span class="nav-number">7.1.</span> <span class="nav-text">栈帧组成之局部变量表</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#垃圾回收"><span class="nav-number">8.</span> <span class="nav-text">垃圾回收</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-标记-清除算法"><span class="nav-number">8.1.</span> <span class="nav-text">1.**标记-**清除算法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-复制算法"><span class="nav-number">8.2.</span> <span class="nav-text">2.**复制算法**</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-标记-整理算法"><span class="nav-number">8.3.</span> <span class="nav-text">3.**标记-**整理算法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-分代收集算法"><span class="nav-number">8.4.</span> <span class="nav-text">4.**分代收集算法**</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#GC-的执行机制"><span class="nav-number">8.5.</span> <span class="nav-text">GC**的执行机制**</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#为什么要运用分代垃圾回收策略?"><span class="nav-number">8.6.</span> <span class="nav-text">为什么要运用分代垃圾回收策略?</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#类加载过程"><span class="nav-number">9.</span> <span class="nav-text">类加载过程</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#加载:完成三件事"><span class="nav-number">9.1.</span> <span class="nav-text">加载:完成三件事</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#验证:四个阶段的检验动作"><span class="nav-number">9.2.</span> <span class="nav-text">验证:四个阶段的检验动作</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-文件格式验证"><span class="nav-number">9.2.1.</span> <span class="nav-text">1.文件格式验证</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-元数据验证"><span class="nav-number">9.2.2.</span> <span class="nav-text">2.元数据验证</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-字节码验证"><span class="nav-number">9.2.3.</span> <span class="nav-text">3.字节码验证</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-符号引用验证"><span class="nav-number">9.2.4.</span> <span class="nav-text">4.符号引用验证</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#准备:为类变量(static)分配内存并设置类变量的初始值。"><span class="nav-number">9.3.</span> <span class="nav-text">准备:为类变量(static)分配内存并设置类变量的初始值。</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#解析:将常量池内的符号引用替换为直接引用的过程。"><span class="nav-number">9.4.</span> <span class="nav-text">解析:将常量池内的符号引用替换为直接引用的过程。</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#初始化"><span class="nav-number">9.5.</span> <span class="nav-text">初始化</span></a></li></ol></li></ol></div>
</div>
</section>
<!--/noindex-->
</div>
</aside>
</div>
</main>
<footer id="footer" class="footer">
<div class="footer-inner">
<script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<div class="copyright">© 2017 — <span itemprop="copyrightYear">2019</span>
<span class="with-love">
<i class="fa fa-user"></i>
</span>
<span class="author" itemprop="copyrightHolder">小蜜蜂</span>
<span class="post-meta-divider">|</span>
<span class="post-meta-item-icon">
<i class="fa fa-area-chart"></i>
</span>
<span class="post-meta-item-text">Site words total count:</span>
<span title="Site words total count">88.8k</span>
</div>
<div class="powered-by">
<i class="fa fa-user-md"></i><span id="busuanzi_container_site_uv">
本站访客数:<span id="busuanzi_value_site_uv"></span>
</span>
</div>
<script>
var seconds = 1000;
var minutes = seconds * 60;
var hours = minutes * 60;
var days = hours * 24;
var years = days * 365;
var birthDay = Date.UTC(2017,09,17,00,00,00); // 这里设置建站时间
setInterval(function() {
var today = new Date();
var todayYear = today.getFullYear();
var todayMonth = today.getMonth()+1;
var todayDate = today.getDate();
var todayHour = today.getHours();
var todayMinute = today.getMinutes();
var todaySecond = today.getSeconds();
var now = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
var diff = now - birthDay;
var diffYears = Math.floor(diff/years);
var diffDays = Math.floor((diff/days)-diffYears*365);
var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
document.getElementById('showDays').innerHTML="本站已运行 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
}, 1000);
</script>
<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js">
</script>
<div class="busuanzi-count">
<script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<span class="site-uv">
<i class="fa fa-user"></i>
<span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
</span>
<span class="site-pv">
<i class="fa fa-eye"></i>
<span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
</span>
</div>
</div>
</footer>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
<span id="scrollpercent"><span>0</span>%</span>
</div>
</div>
<script type="text/javascript">
if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
window.Promise = null;
}
</script>
<script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
<script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
<script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
<script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
<script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
<script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
<script type="text/javascript" src="/lib/canvas-nest/canvas-nest.min.js"></script>
<script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>