抽象
毕加索的牛抽象过程,一步一步隐藏细节
毕加索的牛抽象过程,一步一步隐藏细节
Java 程序以虚拟机为中介,运行于各平台上,实现跨平台的特性
Sun Classic JVM,纯解释型 JVM 实现
Exact VM
现代高性能虚拟机的雏形
两级即时编译器
编译器和解释器混合工作模式
准确式内存
(虚拟机可以知道内存位置的数据具体类型,reference还是value,GC时准确判断可达 )Sun 收购 Longview Technologies的 HostSpot JVM,成 JDK1.3 及之后的默认虚拟机
热点代码探测
能力
BEA JRockit
IBM J9
AOT编译
class data sharing
(一些核心类在每个JVM间共享)
oracle jdk8 的 HostSpot
以前的HotSpot VM与JRockit VM的合并版
JRockit 一些有价值的功能在HotSpot重新实现一遍。移除PermGen、Java Flight Recorder、jcmd等都属于合并项目的一部分
Zing VM
gc C4: The Continuously Concurrent Compacting Collector
利用之前收集到的profile数据,引导JVM在启动后快速达到稳定的高性能水平,减少启动后从解释执行到JIT编译的等待时间
找出代码热点到对象分配监控、锁竞争监控等
手动GC 易产生内存泄漏,直到内存溢出
引用计数
标记清除
现代垃圾回收算法的思想基础
回收后的空间是不连续的
,之后在不连续的内存空间中分配的效率要低于连续的空间
经典标记复制
解决标记清除算法内存回收后不连续的问题而衍生
jvm
JVM 很多垃圾回收器都用到标记复制思想,为解决经典标记复制算法中内存折半问题,JVM 将内存划分为 3 个区
from 和 to 大小相同,地位相等,且可角色互换
from 和 to 也被称为 survivor 空间,即幸存者空间,用于存放未被回收的对象
GC 时,从根节点出发,标记 eden 和 from 区所有存活对象,然后将这些对象复制到 to 区。而下次进行垃圾回收时,to 和 from 区角色互换,将 to 区 和 eden 区的幸存对象复制到 from 区
通过这种方法,解决经典标记复制算法中内存折半问题
通过调整 eden 区,from 区和 to 区的比例,来控制内存的利用率
标记压缩
新生代: 复制算法的高效性建立在存活对象少、垃圾对象多的前提下
老年代: 大部分对象都是存活对象,再用复制算法, 复制成本高
和标记清除一样, 可达标记,但之后, 不只清理未标记的对象, 而将所有的存活对象压缩到内存的一端,之后, 清理边界外所有的空间
既避免了碎片的产生, 又不需要两块相同的内存空间,性价比高
所以标记复制算法和标记压缩算法分别代表了空间换时间和时间换空间思想,并分别活跃在各自擅长的场景中
基本作用是保护临界区资源不会被多个线程同时访问而受到破坏
通过锁, 可以让多个线程排队, 一个一个地进入临界区访问目标对象, 使目标对象的状态总是保持一致
synchronized 方法和 synchronized 代码块:
public class Test {
public void synchronizedBlock() {
synchronized (this) {
System.out.println("synchronizedMethod");
}
}
public synchronized void synchronizedMethod() {
System.out.println("synchronizedMethod");
}
}
从字节码中,编译器会将同步代码块用 monitorenter
和 monitorexit
包裹
同步方法,通过函数的的 access flags
进行标识,当执行有 synchronized
标识的函数时,最后也会调用 monitorenter
和 monitorexit
基本一样的逻辑
类似于 C 结构体描述,统一用无符号整数作为基本数据类型
u1、u2、u4、u8 表示无符号单字节、2 、4 、8 字节,字符串用 u1 数组进行表示
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
一些 linux 命令行神器
os很多思想、经典算法都可在日常开发各种工具或框架中找到它们的影子
学好OS提高思考深度及对技术理解力
一般单个虚拟地址空间就比物理内存要大,另每个进程都有自身的虚拟地址空间
内核和 CPU 必须考虑如何将实际可用的物理内存映射到虚拟地址空间的区域。一般用页表
来为物理地址分配虚拟地址
虚拟地址关系到进程的用户空间和内核空间,而物理地址用来寻址实际可用的内存
物理内存页经常被称为页帧
,而页一般用来指虚拟地址空间的页
连续(块式)
为用户程序分配一个连续
的内存空间
非连续(页式 和 段式)
允个程序使用的内存分布在离散或者说不相邻
的内存中
块式管理 :
远古时代将内存分为几个固定大小的块,每个块中只包含一个进程
如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,称为碎片
页式管理 :
相比块式管理的划分力度更大,提高内存利用率,减少碎片
通过 页表
对应逻辑地址和物理地址
段式管理 :
页式管理虽然提高了内存利用率,但是页式管理其中的页实际并无任何实际意义
段式管理把主存分为一段段的,每一段的空间又要比一页的空间小很多
最重要的是段是有实际意义的,如,主程序段 MAIN、子程序段 X、数据段 DATA 及栈段 STACK 等
段页式管理机制
结合段式管理和页式管理的优点。把主存先分成若干段,每个段又分成若干页,也就是说 段与段之间以及段的内部的都是离散的
假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框
这段内存上不能找到连续的5个空闲的页框,就会去另一段内存上去寻找5个连续的页框,久而久之形成了页框的浪费
并发编程无声的性能杀手
数据在内存中以 page 为单位存在;在cache 里以 cache line 为单位
伪共享:缓存系统以 cache line为单位存储,多线程修改互相独立的变量时,如果这些变量共享同一个cache line,就会无意中影响彼此的性能