《Java特种兵》学习笔记
一、功底
1.1 编译期优化
String a = "a" + "b" + 1;
String b = "ab1";
println(a == b); // true 编译期优化
String a = "a";
final String c = "a";
//a并不是一个常量,而是局部变量,字节码增强技术就可以修改a的实际赋值
String b = a + "b";
String d = c + "b"; //final
//1.编译器不会看方法内部做了什么,2.递归深度不可预测
//3.返回的是对常量引用的拷贝,不是final的,可以修改
String e = getA() + "b";
String compare = "ab";
println(b == compare); //fasle
println(d == compare); //true
println(e == compare); //fasle
private final static String getA() {
return "a";
}
//String b = a + "b" 的实际编译效果
StringBuilder temp = new StringBuilder();
String b = temp.append(a).append("b");
1.2 Intern
public native String intern();
与string pool关联,加锁寻找string字符串,用equals方法判断是否是目标字符串
Jdk1.6: string pool在 Perm Gen中
Jdk1.7:string pool在堆中
public static void test3() {
String a = "a";
String b = a + "b"; //a是变量,new StringBuilder().append(a).append("b");
String c = "ab"; //在string pool中新建ab字符串
String d = new String(b);//新对象
println(b == c); //F
println(c == d); //F
println(c == d.intern()); //True:intern:寻找string pool中的ab,返回地址,没有则创建后返回地址
println(b.intern() == d.intern()); //True:intern:寻找string pool中的ab,返回地址,没有则创建后返回地址
}
老年代是否可以独自清理?而新生代不清理?
1.3 StringBuilder
StringBuilder stringBuilder = new StringBuilder();
for (...) {
//最坏的情况是它所占用的内存空间接近Old区域1/3时发生扩容,导致OOM
stringBuilder.append(string);
}
stringBuilder在append扩容的时候,取max(2倍,count+string.length)
,所以在小字符串append大字符串时,扩容的空间刚刚足够,而大字符串append小字符串时,就会多出大量的内存空间
1.4 大量判定是|否操作
举例:java字节码中的类修饰符,以下都是十六进制,只取后四位显示
public:0001
static:0100
final:1000
对数字取&操作,不为0时就是true
若判断 public static final
, 先取或 public_static_final=public|static|final
;判断(value& public_static_final)== public_static_final
1.5 数据cache
类型 | Cache范围 |
---|---|
Integer | -128 ~127 |
Short | -128 ~127 |
Long | -128 ~127 |
Float double | 无 |
Byte | 256个值 |
二、计算机工作原理
2.1 栈
存储局部变量中的基本数据类型,新建对象时,储存对象引用,而对象是在堆中创建
Jvm发出指令请求,OS完成具体计算,jvm自身无法做计算
2.2 Cache line
通常以连续64位字节为单位进行cache的
如数组获取,当取二维数组a[0][0]时,cache line操作通常会将一些临近的数组元素cache到CPU缓存中,故而连续访问a[0][0],a[0][1]…时,这些连续的数值只要cache一次
2.3 缓存一致性协议
同一份数据cache在多个cpu中时,要求数据读写一致,多个CPU之间要遵循缓存共享的一致性协议
CPU读写数据时都会广播,其他CPU监听,并保存数据一致性
2.4 内存
所有程序中使用的地址都是虚拟地址(逻辑地址),在不同的进程中可以重复
物理地址:每个进程有一段内存区域,起始地址+逻辑地址=物理地址
OS预先给jvm分配-xms大小的内存空间,而不是立即分配一个-xmx大小的空间,许多空间是真正使用时才分配的(启动java时,-xmx设置比物理内存大都可以)
2.5 磁盘
每秒读取的次数IOPS越大越好
顺序读写,减少定位延迟
Java中的日志读写工具,会将日志替换为buffer的append方式,将日志写入一个缓冲区,由专门的程序实现写操作,或者只在缓冲区已满的时候写入磁盘,尽量一次写入多条数据,顺序IO,减少硬盘寻道寻址
三、JVM
Old区域更大一些
静态数据存放于方法区
String对象的intern方法将string对象拷贝到常量池
3.1 类字节码
类常量池
方法:编译时会自动生成构造方法字节码
略过先
3.2 Class字节码加载器
- 继承关