JVM机制
注意:在JDK1.8运行常量池移到了堆中,元空间取代了永久代。元空间并不在虚拟机中,而是使用本地内存。
内存结构
程序计数器
程序计数器是用于存放下一条指令的地址。
栈
线程私有,每个线程对应一个Java虚拟机栈,其生命周期与线程同进同退。每个Java方法在被调用的时候都会创建一个栈帧,并入栈。一旦完成调用,则出栈。所有的的栈帧都出栈后,线程也就完成了使命。
堆
类的加载
将类的.class文件中的二进制数据读入到内存中,将其放在方法区内,然后在堆区创建一个对象,用来封装类在方法区内的数据结构。
过程
- 加载(查找并加载类的二进制数据本地加载,网络加载-applet,jar包,反射)
- 验证(文件格式验证,元数据验证,字节码验证和符号引用验证)
- 准备(为类的静态变量分配内存并将其初始化为默认值)
- 解析(符号引用->直接引用)
- 初始化
- 创建类的实例(new的方式)
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射(如 Class.forName(“com.shengsiyuan.Test”))
- 初始化某个类的子类,则其父类也会被初始化
- Java虚拟机启动时被标明为启动类的类(JavaTest),直接使用 java.exe命令来运行某个主类。
GC回收
对象存活判断
引用计数
可达性分析
根(GC Roots):
- 栈(栈帧中的本地变量表)中引用的对象。
- 静态成员
- 常量引用的对象(全局变量)
- 本地方法栈中JNI(一般说的Native方法)引用的对象
回收算法
- 标记-清除。(CMS收集器[并发])
- 标记-整理:既不内存折半,也不产生内存碎片,适合年老代的垃圾回收。Serial Old收集器、Parallel Old收集器
- 标记-复制:适合年轻代。Serial收集器、ParNew收集器
内存泄漏(长生命对象引用短生命对象)
静态集合类,单例对象引用其他对象,各种连接(数据库连接,网络连接,IO连接等没有显示调用close关闭),监听器的使用。
注意事项
- 程序员可以通过 System.gc() 通知GC运行(发出建议,但是无权调用),但是Java规范并不能保证立刻运行。
- finalize方法,是Java提供给程序员用来释放对象或资源的方法,但是尽量少用。