Skip to content

Commit ebb2165

Browse files
committed
finish chapter16
1 parent 30f647f commit ebb2165

9 files changed

Lines changed: 173 additions & 172 deletions

File tree

JVM/第九章_方法区/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ public class OOMTest extends ClassLoader {
136136
对每个加载的类型(类 class、接口 interface、枚举 enum、注解 annotation),JVM 必须在方法区中存储以下类型信息:
137137

138138
- 这个类型的完整有效名称(全名=包名.类名)
139-
- 这个类型直接父类的完整有效名(对于interface或是java.lang.object,都没有父类)
140-
- 这个类型的修饰符(public,abstract,final的某个子集
139+
- 这个类型直接父类的完整有效名(对于 interface 或是 java.lang.object,都没有父类)
140+
- 这个类型的修饰符(public,abstract,final 的某个子集
141141
- 这个类型直接接口的一个有序列表
142142

143143
### 域(Field)信息

JVM/第十一章_直接内存/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# 直接内存 Direct Memory
22

3-
不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。
3+
不是虚拟机运行时数据区的一部分,也不是《Java 虚拟机规范》中定义的内存区域。
44

55
**直接内存是在 Java 堆外的、直接向系统申请的内存区间。**
66

7-
来源于 NIO ,通过存在堆中的 DirectByteBuffer 操作 Native 内存
7+
来源于 NIO ,通过存在堆中的 DirectByteBuffer 操作 Native 内存
88

99
通常,访问直接内存的速度会优于 Java 堆。即读写性能高。
1010

11-
- 因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存
11+
- 因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存
1212
- Java 的 NIO 库允许 Java 程序使用直接内存,用于数据缓冲区
1313

1414
使用下列代码,直接分配本地内存空间

JVM/第十七章_垃圾回收器/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 垃圾回收器
22

3-
## GC分类与性能指标
3+
## GC 分类与性能指标
44

55
垃圾收集器没有在规范中进行过多的规定,可以由不同的厂商、不同版本的 JVM 来实现。
66

JVM/第十三章_StringTable/README.md

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# StringTable
22

3-
## String的基本特性
3+
## String 的基本特性
44

55
- String:字符串,使用一对 "" 引起来表示
66
- String s1 = "mogublog" ; // 字面量的定义方式
@@ -11,7 +11,7 @@
1111

1212
### 为什么 JDK 9 改变了结构
1313

14-
String 类的当前实现将字符存储在 char 数组中,每个字符使用两个字节(16位)。从许多不同的应用程序收集的数据表明,字符串是堆使用的主要组成部分,而且,大多数字符串对象只包含拉丁字符。这些字符只需要一个字节的存储空间,因此这些字符串对象的内部 char 数组中有一半的空间将不会使用。
14+
String 类的当前实现将字符存储在 char 数组中,每个字符使用两个字节(16 位)。从许多不同的应用程序收集的数据表明,字符串是堆使用的主要组成部分,而且,大多数字符串对象只包含拉丁字符。这些字符只需要一个字节的存储空间,因此这些字符串对象的内部 char 数组中有一半的空间将不会使用。
1515

1616
> Motivation
1717
>
@@ -32,19 +32,19 @@ private final char value[];
3232
private final byte[] value
3333
```
3434

35-
同时基于 String 的数据结构,例如 StringBuffer 和 StringBuilder 也同样做了修改
35+
同时基于 String 的数据结构,例如 StringBuffer 和 StringBuilder 也同样做了修改
3636

37-
### String的不可变性
37+
### String 的不可变性
3838

3939
String:代表不可变的字符序列。简称:不可变性。
4040

4141
- 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的 value 进行赋值。
4242
- 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的 value 进行赋值。
4343
- 当调用 String 的 replace() 方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的 value 进行赋值。
4444

45-
通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
45+
通过字面量的方式(区别于 new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
4646

47-
代码
47+
代码
4848

4949
```java
5050
public class StringTest1 {
@@ -86,7 +86,7 @@ public class StringTest1 {
8686
}
8787
```
8888

89-
运行结果
89+
运行结果
9090

9191
```
9292
true
@@ -131,37 +131,37 @@ best
131131

132132
### 注意
133133

134-
**字符串常量池是不会存储相同内容的字符串的**
134+
**字符串常量池是不会存储相同内容的字符串的**
135135

136-
String 的 String Pool 是一个固定大小的 Hashtable ,默认值大小长度是1009。如果放进 String Pool 的 String 非常多,就会造成 Hash 冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用 String.intern 时性能会大幅下降。
136+
String 的 String Pool 是一个固定大小的 Hashtable ,默认值大小长度是 1009。如果放进 String Pool 的 String 非常多,就会造成 Hash 冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用 String.intern 时性能会大幅下降。
137137

138-
使用 -XX:StringTablesize 可设置 StringTable 的长度
138+
使用 -XX:StringTablesize 可设置 StringTable 的长度
139139

140-
在 JDK 6 中 StringTable 是固定的,就是 1009 的长度,所以如果常量池中的字符串过多就会导致效率下降很快。StringTablesize 设置没有要求
140+
在 JDK 6 中 StringTable 是固定的,就是 1009 的长度,所以如果常量池中的字符串过多就会导致效率下降很快。StringTablesize 设置没有要求
141141

142-
在 JDK 7 中,StringTable 的长度默认值是 60013 ,StringTablesize 设置没有要求
142+
在 JDK 7 中,StringTable 的长度默认值是 60013 ,StringTablesize 设置没有要求
143143

144-
在 JDK 8 中,StringTable 可以设置的最小值为 1009
144+
在 JDK 8 中,StringTable 可以设置的最小值为 1009
145145

146-
## String的内存分配
146+
## String 的内存分配
147147

148-
在 Java 语言中有8种基本数据类型和一种比较特殊的类型 String 。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。
148+
在 Java 语言中有 8 种基本数据类型和一种比较特殊的类型 String 。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。
149149

150-
常量池就类似一个 Java 系统级别提供的缓存。8种基本数据类型的常量池都是系统协调的**String 类型的常量池比较特殊。它的主要使用方法有两种。**
150+
常量池就类似一个 Java 系统级别提供的缓存。8 种基本数据类型的常量池都是系统协调的**String 类型的常量池比较特殊。它的主要使用方法有两种。**
151151

152152
- 直接使用双引号声明出来的 String 对象会直接存储在常量池中。
153153
- 比如:String info = "atguigu.com";
154154

155155
- 如果不是用双引号声明的 String 对象,**可以使用 String 提供的 intern() 方法**
156156

157-
Java 6 及以前,字符串常量池存放在永久代
157+
Java 6 及以前,字符串常量池存放在永久代
158158

159-
Java 7 中 Oracle 的工程师对字符串池的逻辑做了很大的改变,即将**字符串常量池的位置调整到 Java 堆内**
159+
Java 7 中 Oracle 的工程师对字符串池的逻辑做了很大的改变,即将**字符串常量池的位置调整到 Java 堆内**
160160

161161
- 所有的字符串都保存在堆(Heap)中,和其他普通对象一样,这样可以让你在进行调优应用时仅需要调整堆大小就可以了。
162162
- 字符串常量池概念原本使用得比较多,但是这个改动使得我们有足够的理由让我们重新考虑在 Java 7 中使用 String.intern()。
163163

164-
Java 8 元空间,字符串常量在堆
164+
Java 8 元空间,字符串常量在堆
165165

166166
![image-20200711093546398](https://gitee.com/xlshi/blog_img/raw/master/img/20201012122412.png)
167167

@@ -264,7 +264,7 @@ s1 + s2 的执行细节
264264
| | 线程安全 | 线程不安全 |
265265
| | 多线程操作字符串 | 单线程操作字符串 |
266266

267-
注意,我们左右两边如果是变量的话,就是需要 new StringBuilder 进行拼接,但是如果使用的是 final 修饰,则是从常量池中获取。所以说拼接符号左右两边都是字符串常量或常量引用 则仍然使用编译器优化。也就是说被 final 修饰的变量,将会变成常量,类和方法将不能被继承
267+
注意,我们左右两边如果是变量的话,就是需要 new StringBuilder 进行拼接,但是如果使用的是 final 修饰,则是从常量池中获取。所以说拼接符号左右两边都是字符串常量或常量引用 则仍然使用编译器优化。也就是说被 final 修饰的变量,将会变成常量,类和方法将不能被继承
268268

269269
- 在开发中,能够使用 final 的时候,建议使用上
270270

@@ -278,7 +278,7 @@ public static void test4() {
278278
}
279279
```
280280

281-
运行结果
281+
运行结果
282282

283283
```
284284
true
@@ -302,26 +302,26 @@ public static void method2(int highLevel) {
302302
}
303303
```
304304

305-
方法1耗费的时间:4005ms,方法2消耗时间:7ms
305+
方法 1 耗费的时间:4005ms,方法 2 消耗时间:7ms
306306

307307
结论:
308308

309309
- 通过 StringBuilder 的 append() 方式添加字符串的效率,要远远高于 String 的字符串拼接方法
310310

311-
好处
311+
好处
312312

313313
- StringBuilder 的 append 的方式,自始至终只创建一个 StringBuilder 的对象
314-
- 对于字符串拼接的方式,还需要创建很多 StringBuilder 对象和调用 toString 时候创建的String 对象
314+
- 对于字符串拼接的方式,还需要创建很多 StringBuilder 对象和调用 toString 时候创建的 String 对象
315315
- 内存中由于创建了较多的 StringBuilder 和 String 对象,内存占用过大,如果进行 GC 那么将会耗费更多的时间
316316

317-
改进的空间
317+
改进的空间
318318

319-
- 我们使用的是 StringBuilder 的空参构造器,默认的字符串容量是16,然后将原来的字符串拷贝到新的字符串中, 我们也可以默认初始化更大的长度,减少扩容的次数
319+
- 我们使用的是 StringBuilder 的空参构造器,默认的字符串容量是 16,然后将原来的字符串拷贝到新的字符串中, 我们也可以默认初始化更大的长度,减少扩容的次数
320320
- 因此在实际开发中,我们能够确定,前前后后需要添加的字符串不高于某个限定值,那么建议使用构造器创建一个阈值的长度
321321

322322
## intern() 的使用
323323

324-
intern() 是一个 native 方法,调用的是底层 C 的方法
324+
intern() 是一个 native 方法,调用的是底层 C 的方法
325325

326326
字符串池最初是空的,由 String 类私有地维护。在调用 intern() 方法时,如果池中已经包含了由 equals(object) 方法确定的与该字符串对象相等的字符串,则返回池中的字符串。否则,该字符串对象将被添加到池中,并返回对该字符串对象的引用。
327327

@@ -333,13 +333,13 @@ intern() 是一个 native 方法,调用的是底层 C 的方法
333333
String myInfo = new string("I love atguigu").intern();
334334
```
335335

336-
也就是说,如果在任意字符串上调用 String.intern() 方法,那么其返回结果所指向的那个类实例,必须和直接以常量形式出现的字符串实例完全相同。因此,下列表达式的值必定是 true
336+
也就是说,如果在任意字符串上调用 String.intern() 方法,那么其返回结果所指向的那个类实例,必须和直接以常量形式出现的字符串实例完全相同。因此,下列表达式的值必定是 true
337337

338338
```java
339339
"a"+"b"+"c".intern()=="abc"
340340
```
341341

342-
通俗点讲,Interned String 就是确保字符串在内存里只有一份拷贝,这样可以节约内存空间,加快字符串操作任务的执行速度。注意,这个值会被存放在字符串内部池(String Intern Pool)
342+
通俗点讲,Interned String 就是确保字符串在内存里只有一份拷贝,这样可以节约内存空间,加快字符串操作任务的执行速度。注意,这个值会被存放在字符串内部池(String Intern Pool)
343343

344344
```java
345345
/**
@@ -373,7 +373,7 @@ public class StringIntern {
373373

374374
### intern() 的空间效率测试
375375

376-
我们通过测试一下,使用了 intern 和不使用的时候,其实相差还挺多的
376+
我们通过测试一下,使用了 intern 和不使用的时候,其实相差还挺多的
377377

378378
```java
379379
public class StringIntern2 {
@@ -517,7 +517,7 @@ String s2 = "1";
517517
System.out.println(s == s2); // true
518518
```
519519

520-
而对于下面的来说,因为 s3 变量记录的地址是 new String("11"),然后这段代码执行完以后,常量池中不存在 "11",这是 JDK 6 的关系,然后执行 s3.intern() 后,就会在常量池中生成 "11",最后 s4 用的就是 s3 的地址
520+
而对于下面的来说,因为 s3 变量记录的地址是 new String("11"),然后这段代码执行完以后,常量池中不存在 "11",这是 JDK 6 的关系,然后执行 s3.intern() 后,就会在常量池中生成 "11",最后 s4 用的就是 s3 的地址
521521

522522
> 为什么最后输出的 s3 == s4 会为 false 呢?
523523
>
@@ -539,8 +539,6 @@ String s4 = "11";
539539
System.out.println(s3 == s4); // true
540540
```
541541

542-
![image-20200711145925091](images/image-20200711145925091.png)
543-
544542
### 扩展
545543

546544
```java
@@ -550,7 +548,7 @@ s3.intern(); // 然后s3就会从常量池中找,发现有了,就什么事
550548
System.out.println(s3 == s4);
551549
```
552550

553-
我们将 s4 的位置向上移动一行,发现变化就会很大,最后得到的是 false
551+
我们将 s4 的位置向上移动一行,发现变化就会很大,最后得到的是 false
554552

555553
### 总结
556554

@@ -582,14 +580,14 @@ true
582580
false
583581
```
584582

585-
在 JDK 8 中是
583+
在 JDK 8 中是
586584

587585
```
588586
true
589587
true
590588
```
591589

592-
针对下面这题,在 JDK 6 和 JDK 8 中表现的是一样的
590+
针对下面这题,在 JDK 6 和 JDK 8 中表现的是一样的
593591

594592
![image-20200711151433277](https://gitee.com/xlshi/blog_img/raw/master/img/20201012142321.png)
595593

@@ -613,24 +611,25 @@ public class StringGCTest {
613611

614612
## G1 中的 String 去重操作
615613

616-
注意这里说的重复,指的是在堆中的数据,而不是常量池中的,因为常量池中的本身就不会重复
614+
注意这里说的重复,指的是在堆中的数据,而不是常量池中的,因为常量池中的本身就不会重复
617615

618616
### 描述
619617

620618
背景:对许多 Java 应用(有大的也有小的)做的测试得出以下结果:
621-
- 堆存活数据集合里面 String 对象占了25%
619+
- 堆存活数据集合里面 String 对象占了 25%
622620
- 堆存活数据集合里面重复的 String 对象有13.5%
623621

624-
- String 对象的平均长度是45
622+
- String 对象的平均长度是 45
623+
624+
许多大规模的 Java 应用的瓶颈在于内存,测试表明,在这些类型的应用里面,**Java 堆中存活的数据集合差不多 25% 是 String 对象**。更进一步,这里面差不多一半 String 对象是重复的,重复的意思是说:
625625

626-
许多大规模的 Java 应用的瓶颈在于内存,测试表明,在这些类型的应用里面,**Java 堆中存活的数据集合差不多25%是 String 对象**。更进一步,这里面差不多一半 String 对象是重复的,重复的意思是说:
627626
string1.equals(string2) = true。堆上存在重复的 String 对象必然是一种内存的浪费。这个项目将在 G1 垃圾收集器中实现自动持续对重复的 String 对象进行去重,这样就能避免浪费内存。
628627

629628
### 实现
630629

631630
- 当垃圾收集器工作的时候,会访问堆上存活的对象。**对每一个访问的对象都会检查是否是候选的要去重的 String 对象。**
632631
- 如果是,把这个对象的一个引用插入到队列中等待后续的处理。一个去重的线程在后台运行,处理这个队列。处理队列的一个元素意味着从队列删除这个元素,然后尝试去重它引用的 String 对象。
633-
- 使用一个 Hashtable 来记录所有的被 String 对象使用的不重复的 char 数组。当去重的时候,会查这个 Hashtable ,来看堆上是否已经存在一个一模一样的 char 数组。
632+
- 使用一个 Hashtable 来记录所有的被 String 对象使用的不重复的 char 数组。当去重的时候,会查这个 Hashtable,来看堆上是否已经存在一个一模一样的 char 数组。
634633
- 如果存在,String 对象会被调整引用那个数组,释放对原来的数组的引用,最终会被垃圾收集器回收掉。
635634
- 如果查找失败,char 数组会被插入到 Hashtable,这样以后的时候就可以共享这个数组了。
636635

0 commit comments

Comments
 (0)