@@ -96,7 +96,7 @@ Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成
96
96
97
97
** 与程序计数器一样,Java 虚拟机栈也是线程私有的,它的生命周期和线程相同,描述的是 Java 方法执行的内存模型,每次方法调用的数据都是通过栈传递的。**
98
98
99
- ** Java 内存可以粗糙的区分为堆内存(Heap)和栈内存 (Stack), 其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。** (实际上,Java 虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。)
99
+ ** Java 内存可以粗糙的区分为堆内存(Heap)和栈内存 (Stack), 其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。** (实际上,Java 虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。)
100
100
101
101
** 局部变量表主要存放了编译期可知的各种数据类型** (boolean、byte、char、short、int、float、long、double)、** 对象引用** (reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。
102
102
@@ -111,7 +111,7 @@ Java 虚拟机栈也是线程私有的,每个线程都有各自的 Java 虚拟
111
111
112
112
** 扩展:那么方法/函数如何调用?**
113
113
114
- Java 栈可用类比数据结构中栈 ,Java 栈中保存的主要内容是栈帧,每一次函数调用都会有一个对应的栈帧被压入 Java 栈,每一个函数调用结束后,都会有一个栈帧被弹出。
114
+ Java 栈可以类比数据结构中栈 ,Java 栈中保存的主要内容是栈帧,每一次函数调用都会有一个对应的栈帧被压入 Java 栈,每一个函数调用结束后,都会有一个栈帧被弹出。
115
115
116
116
Java 方法有两种返回方式:
117
117
@@ -132,11 +132,11 @@ Java 方法有两种返回方式:
132
132
133
133
Java 虚拟机所管理的内存中最大的一块,Java 堆是所有线程共享的一块内存区域,在虚拟机启动时创建。** 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。**
134
134
135
- Java 世界中“几乎”所有的对象都在堆中分配,但是,随着 JIT 编译期的发展与逃逸分析技术逐渐成熟 ,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。从 JDK 1.7 开始已经默认开启逃逸分析,如果某些方法中的对象引用没有被返回或者未被外面使用(也就是未逃逸出去),那么对象可以直接在栈上分配内存。
135
+ Java 世界中“几乎”所有的对象都在堆中分配,但是,随着 JIT 编译器的发展与逃逸分析技术逐渐成熟 ,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。从 JDK 1.7 开始已经默认开启逃逸分析,如果某些方法中的对象引用没有被返回或者未被外面使用(也就是未逃逸出去),那么对象可以直接在栈上分配内存。
136
136
137
- Java 堆是垃圾收集器管理的主要区域,因此也被称作** GC 堆(Garbage Collected Heap)** . 从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以 Java 堆还可以细分为:新生代和老年代: 再细致一点有:Eden 空间、From Survivor、To Survivor 空间等。** 进一步划分的目的是更好地回收内存,或者更快地分配内存。**
137
+ Java 堆是垃圾收集器管理的主要区域,因此也被称作** GC 堆(Garbage Collected Heap)** 。 从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以 Java 堆还可以细分为:新生代和老年代; 再细致一点有:Eden 空间、From Survivor、To Survivor 空间等。** 进一步划分的目的是更好地回收内存,或者更快地分配内存。**
138
138
139
- 在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常被分为下面三部分 :
139
+ 在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常分为下面三部分 :
140
140
141
141
1 . 新生代内存(Young Generation)
142
142
2 . 老生代(Old Generation)
@@ -170,7 +170,6 @@ JDK 8 版本之后方法区(HotSpot 的永久代)被彻底移除了(JDK1.7
170
170
> uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold;
171
171
> ...
172
172
> }
173
- >
174
173
> ```
175
174
176
175
堆这里最容易出现的就是 OutOfMemoryError 错误,并且出现这种错误之后的表现形式还会有几种,比如:
@@ -247,7 +246,7 @@ JDK 1.8 的时候,方法区(HotSpot 的永久代)被彻底移除了(JDK1
247
246
248
247
** 直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致 OutOfMemoryError 错误出现。**
249
248
250
- JDK1.4 中新加入的 ** NIO(New Input/Output) 类** ,引入了一种基于** 通道(Channel)** 与** 缓存区(Buffer)** 的 I/O 方式,它可以直接使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为** 避免了在 Java 堆和 Native 堆之间来回复制数据** 。
249
+ JDK1.4 中新加入的 ** NIO(New Input/Output) 类** ,引入了一种基于** 通道(Channel)** 与** 缓存区(Buffer)** 的 I/O 方式,它可以直接使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为** 避免了在 Java 堆和 Native 堆之间来回复制数据** 。
251
250
252
251
本机直接内存的分配不会受到 Java 堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。
253
252
@@ -383,10 +382,10 @@ System.out.println(str4 == str5);//false
383
382
** 验证:**
384
383
385
384
``` java
386
- String s1 = new String (" abc" );// 堆内存的地址值
387
- String s2 = " abc" ;
388
- System . out. println(s1 == s2);// 输出 false,因为一个是堆内存,一个是常量池的内存,故两者是不同的。
389
- System . out. println(s1. equals(s2));// 输出 true
385
+ String s1 = new String (" abc" );// 堆内存的地址值
386
+ String s2 = " abc" ;
387
+ System . out. println(s1 == s2);// 输出 false,因为一个是堆内存,一个是常量池的内存,故两者是不同的。
388
+ System . out. println(s1. equals(s2));// 输出 true
390
389
```
391
390
392
391
** 结果:**
@@ -421,15 +420,15 @@ private static class CharacterCache {
421
420
两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。
422
421
423
422
``` java
424
- Integer i1 = 33 ;
425
- Integer i2 = 33 ;
426
- System . out. println(i1 == i2);// 输出 true
427
- Integer i11 = 333 ;
428
- Integer i22 = 333 ;
429
- System . out. println(i11 == i22);// 输出 false
430
- Double i3 = 1.2 ;
431
- Double i4 = 1.2 ;
432
- System . out. println(i3 == i4);// 输出 false
423
+ Integer i1 = 33 ;
424
+ Integer i2 = 33 ;
425
+ System . out. println(i1 == i2);// 输出 true
426
+ Integer i11 = 333 ;
427
+ Integer i22 = 333 ;
428
+ System . out. println(i11 == i22);// 输出 false
429
+ Double i3 = 1.2 ;
430
+ Double i4 = 1.2 ;
431
+ System . out. println(i3 == i4);// 输出 false
433
432
```
434
433
435
434
** Integer 缓存源代码:**
@@ -438,12 +437,11 @@ private static class CharacterCache {
438
437
/**
439
438
*此方法将始终缓存-128 到 127(包括端点)范围内的值,并可以缓存此范围之外的其他值。
440
439
*/
441
- public static Integer valueOf(int i) {
442
- if (i >= IntegerCache . low && i <= IntegerCache . high)
443
- return IntegerCache . cache[i + (- IntegerCache . low)];
444
- return new Integer (i);
445
- }
446
-
440
+ public static Integer valueOf(int i) {
441
+ if (i >= IntegerCache . low && i <= IntegerCache . high)
442
+ return IntegerCache . cache[i + (- IntegerCache . low)];
443
+ return new Integer (i);
444
+ }
447
445
```
448
446
449
447
** 应用场景:**
@@ -452,38 +450,38 @@ private static class CharacterCache {
452
450
2 . Integer i1 = new Integer(40);这种情况下会创建新的对象。
453
451
454
452
``` java
455
- Integer i1 = 40 ;
456
- Integer i2 = new Integer (40 );
457
- System . out. println(i1== i2);// 输出 false
453
+ Integer i1 = 40 ;
454
+ Integer i2 = new Integer (40 );
455
+ System . out. println(i1== i2);// 输出 false
458
456
```
459
457
460
458
** Integer 比较更丰富的一个例子:**
461
459
462
460
``` java
463
- Integer i1 = 40 ;
464
- Integer i2 = 40 ;
465
- Integer i3 = 0 ;
466
- Integer i4 = new Integer (40 );
467
- Integer i5 = new Integer (40 );
468
- Integer i6 = new Integer (0 );
469
-
470
- System . out. println(" i1=i2 " + (i1 == i2));
471
- System . out. println(" i1=i2+i3 " + (i1 == i2 + i3));
472
- System . out. println(" i1=i4 " + (i1 == i4));
473
- System . out. println(" i4=i5 " + (i4 == i5));
474
- System . out. println(" i4=i5+i6 " + (i4 == i5 + i6));
475
- System . out. println(" 40=i5+i6 " + (40 == i5 + i6));
461
+ Integer i1 = 40 ;
462
+ Integer i2 = 40 ;
463
+ Integer i3 = 0 ;
464
+ Integer i4 = new Integer (40 );
465
+ Integer i5 = new Integer (40 );
466
+ Integer i6 = new Integer (0 );
467
+
468
+ System . out. println(" i1=i2 " + (i1 == i2));
469
+ System . out. println(" i1=i2+i3 " + (i1 == i2 + i3));
470
+ System . out. println(" i1=i4 " + (i1 == i4));
471
+ System . out. println(" i4=i5 " + (i4 == i5));
472
+ System . out. println(" i4=i5+i6 " + (i4 == i5 + i6));
473
+ System . out. println(" 40=i5+i6 " + (40 == i5 + i6));
476
474
```
477
475
478
476
结果:
479
477
480
478
```
481
- i1=i2 true
482
- i1=i2+i3 true
483
- i1=i4 false
484
- i4=i5 false
485
- i4=i5+i6 true
486
- 40=i5+i6 true
479
+ i1=i2 true
480
+ i1=i2+i3 true
481
+ i1=i4 false
482
+ i4=i5 false
483
+ i4=i5+i6 true
484
+ 40=i5+i6 true
487
485
```
488
486
489
487
解释:
0 commit comments