虚拟机
Classic VM
HotSpot
虚拟机规范
VM由编译器和执行器两个部分组成
- 编译器:.class文件执行过程中,将.class文件编译为可执行文件,通过分层编译将热点代码编译本地可执行代码,提高执行效率
- 标准编译
- 分层编译,C1,C2,C3,OSR(on-stack-replace)
- 执行器:进行程序的执行,内存的管理,VM中内存模型如下
- 1.引用计数器,属于线程
- 2.栈:虚拟机堆栈 (Virtual Machine stack) 调用Java方法的栈,本地方法堆栈(native method stack)调用native方法的栈
- 3.方法区:存储class,常量,静态变量,运行时常量池(Runtime Constant Pool),存放在编译期间生成的常量(Constant Pool Table)
- 4.堆(heap):存放 new 出来的Object
- 5.直接内存(Direct Memory)不属于Java虚机中定义的内存空间,DirectByteBuffer引用堆外内存,避免了Java堆和Native堆来回的数据拷贝
VM中的内存按照能否被线程访问分为
-
线程隔离:引用计数器,栈,线程独占访问的
-
线程共享:方法区,堆,直接内存,所有的线程都可以访问
HotSpot
对象创建
1、Class的加载:classLoader,相关类型class信息加载,初始化静态变量,
2、对象分配内存:
3、对象初始化,init<构造>
对象模型
- 头:(Header)
1、自身运行时数据:(Mark Word)
2、类型指针:指向class类 - 体:(Instance)
1、属性,FieldsAllocationStyle,要有字段对齐 - 对齐:(Padding)
对象访问:
1.指针方式:直接指向生成的对象,垃圾收集时候需要改变每个reference的值,但是只有一次访问
2.句柄方式:在堆中划分出句柄池,存放句柄与对象的双向映射关系,垃圾收集时候,只需要改句柄,但是要经过一次访问转换
垃圾回收
内存的垃圾回收,主要做三件事情,哪些内存可以回收,怎么回收,什么时候回收
-
1、哪些可以回收:Mark
引用计数法(Reference Counting)
可达性分析(Reachability Analysis):确定GC Root作为起点,向下搜索,没有被搜素到对象,称为不可达对象
GC Root对象:
1、虚拟机堆栈中,栈帧存在的对象
2、方法区中,Class对象的静态变量引用的对象
3、方法区中,Class对象常量对象
4、本地方法栈中,栈帧存在的对象
引用类型:新概念
Java神存在:finalize()方法,这个方法只会调用一次 -
2、怎么回收:Collect
sweep 碎片,效率高
copy 空间浪费,效率高
compact=(sweep+copy) 效率低,无碎片 -
3、什么时候回收:When
安全点:到安全点,所有的线程到稳定状态
安全区域:没明白怎么实现的
并行计算:
Sumatra Java多核并行计算引擎,
在 Java 7 以前,我们需要根据程序的特性选择对应的即时编译器。对于执行时间较短的,或者对启动性能有要求的程序,我们采用编译效率较快的 C1,对应参数 -client。
对于执行时间较长的,或者对峰值性能有要求的程序,我们采用生成代码执行效率较快的 C2,对应参数 -server。
针对新生代的垃圾回收器共有三个:Serial,Parallel Scavenge 和 Parallel New。这三个采用的都是标记 - 复制算法。其中,Serial 是一个单线程的,Parallel New 可以看成 Serial 的多线程版本。Parallel Scavenge 和 Parallel New 类似,但更加注重吞吐率。此外,Parallel Scavenge 不能与 CMS 一起使用。
针对老年代的垃圾回收器也有三个:刚刚提到的 Serial Old 和 Parallel Old,以及 CMS。Serial Old 和 Parallel Old 都是标记 - 压缩算法。同样,前者是单线程的,而后者可以看成前者的多线程版本。由于 G1 的出现,CMS 在 Java 9 中已被废弃
可移植操作系统接口(英语:Portable Operating System Interface,缩写为POSIX)
线程的 阻塞 唤醒 自旋(忙等操作)
内存分配方式:
- 指针碰撞(Bump The Pointer)数组式的内存分配
- 空闲列表(Free List) 列表的形式分配内存
事物性:
- 重锁
- 轻量锁:CAS(Compare And Set)
配置项
- -XX:+UsePSAdaptiveSurvivorSizePolicy 根据生成对象的速率,以及 Survivor 区的使用情况动态调整 Eden 区和 Survivor 区的比例。
- -XX:SurvivorRatio 来固定这个比例。但是需要注意的是,其中一个 Survivor 区会一直为空,因此比例越低浪费的堆空间将越高。
- -XX:+UseTLAB (Thread Local Allocation Buffer,对应虚拟机参数 -XX:+UseTLAB,默认开启)每个线程可以向 Java 虚拟机申请一段连续的内存,比如 2048 字节,作为线程私有的 TLAB。
- -XX:+MaxTenuringThreshold 那么该对象将被晋升(promote)至老年代
- -XX:TargetSurvivorRatio 另外,如果单个 Survivor 区已经被占用了 50%,那么较高复制次数的对象也会被晋升至老年代。