一、jvm规范运行时数据区
程序计数器、虚拟机栈、本地方法栈、堆、方法区(非堆/静态存储区)。
线程私有:程序计数器、虚拟机栈、本地方法栈
线程共享:堆、方法区
程序计数器:它就是为多线程准备的,程序计数器是每个线程独有的,所以是线程安全的。记录每个线程的执行情况,保证线程切换后能恢复到正确位置。
虚拟机栈:经常有人把Java内存划分为堆内存(Heap)和栈内存(Stack)。其中所值的“栈”,就是现在讲的虚拟机栈,或者说是局部变量表。
本地方法栈:与虚拟机栈所发挥的作用类似,是为虚拟机使用的Native方法服务。
java堆:Java堆是GC的主要场所。细分为:新生代和老年代:新生代又分为Eden区、S0、S1。
方法区:也叫非堆、或者(静态存储区)用于存储类信息、常量、静态变量等。通俗的讲就是编译后的class文件信息。运行时常量池也是方法区的一部分。
二、对象已死吗
判断对象是否存活的算法有引用计数法、可达性分析。
1、引用计数法
给对象添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效,计数器值就减1。
不能解决对象之间相互循环引用的问题。
2、可达性分析
通过一系列的称为“GC Roots”的对象作为起始点(根节点),从起始点开始开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Root没有任何引用链相连,证明此对象不可用。
根节点:类加载器、常量、static成员。
三、垃圾收集算法
介绍几种算法的思想。
1、标记清除
先标记可回收对象,然后回收。它的主要不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量不连续的内存碎片。
2、复制算法
将内存分成两块,每次只使用其中的一块,当这一块内存用完了,就将还存活的对象复制到另一款上,然后把使用过的内存空间一次清理掉。效率高、空间利用率不高。
商业虚拟机采用复制算法来回收新生代,新生代中的对象大部分都是朝生夕死,对象存活率较低,Eden:S0:S1=8:1:1
3、标记整理
标记可回收对象,将存活对象向一段移动。没有碎片,时间长
4、分代收集
Young区(新生代)用复制算法
Old(老年代)用标记清除或标记整理
四、垃圾收集器
垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。主要介绍CMS收集器、G1收集器
1、CMS收集器
CMS(Concurrent Mark Sweep)关注停顿时间,从名字(包含“Mark Sweep”)可以看出,CMS收集器是基于“标记--清除”算法实现的。
2、G1收集器(Garbage First)
采用分代收集
五、内存分配与回收策略
对象优先分配在Eden区,没有足够空间时,进行Minor GC,存活的对象进入S0,Eden区被清空。等Eden区又没有足够空间时,进行Minor GC,Eden和S0的存活对象进入S1,Eden和S0被清空。如果对象历经16次Minor GC,仍然存活,直接进入老年代。
大对象直接进入老年代。
七、虚拟机类加载机制
1、加载
根据类的全限定名加载其class文件,转化为Class对象
2、连接
①验证:确保类文件的正确性,比如文件格式。
②准备:为所有静态变量分配内存空间,并设置初始值。
③解析:将常量池中的符合引用转换为直接引用。
3、初始化:给类的静态变量赋值(编码阶段给定的值)
八、类加载器
1、启动类加载器(Bootstrap ClassLoader):
2、扩展类加载器(Extension ClassLoader):
3、应用程序类加载器(Application ClassLoader)
双亲委派模型:
九、FullGC
1、老年代空间不足时
2、老年代没有足够大的连续空间
3、System.gc()方法的调用。
十、常用命令
1、内存溢出(out of memory)
jmap导出dump文件,用eclipse memory analyzer进行分析,分析对象的数量和占用内存。
2、处理死循环
jstack导出文件,top命令找出进程对应的所有线程,找到占用cpu多的线程
3、处理死锁
jstack导出文件,找到文件的最后,会看到一个deadlock,死锁的线程。
十 一、何时触发初始化
1、通过new关键字会导致类的初始化
2、初始化子类会导致父类的初始化
3、启动类:执行main函数所在的类会导致该类的初始化
接下来看一段代码,满足以上三种情况。有三个类:Parent、Children、Test。
public class Parent {
static {
System.out.println("static Parent");
}
Parent(){
System.out.println("创建对象parent");
}
}
Children:
public class Children extends Parent {
static {
System.out.println("static Children");
}
Children(){
System.out.println("创建对象children");
}
}
Test:
public class Test {
static {
System.out.println("static Test");
}
public static void main(String[] args) {
Children children = new Children();
//Parent parent = new Parent();
}
}
最终打印结果如下:
4、访问类的静态变量
5、访问类的静态方法
6、对某个类进行反射操作
静态方法代码:
public class StaticMethod {
static {
System.out.println("static staticMethod");
}
static void method(){
System.out.println("");
}
}
静态变量代码:
public class StaticVar {
static {
System.out.println("static staticVar");
}
static String a;
}
Test类:
public class Test {
public static void main(String[] args) {
StaticMethod.method();
String a = StaticVar.a;
}
}
最终打印结果如下: