目录
1. 面向对象的内存分析
Java虚拟机内存模型概念
1.1 从属于线程的内存区域
JVM的内存划分中,有部分区域是线程私有的,有部分是属于整个JVM进程。
-
程序计数器,在JVM规范中,每个线程都有自己的程序计数器。存储当前线程正在执行的Java方法的JVM指令地址,即字节码的行号,如果正在执行Native方法,则这个计数器为空。
-
Java虚拟机栈,同样也属于线程私有区域,每个线程在创建的时候都会创建一个虚拟机栈。虚拟机栈内部保持一个个栈帧,每次方法调用都会进行压栈,JVM对栈帧的操作只有出栈和压栈两种,方法调用结束时会进行出栈操作。
-
本地方法栈,不管
1.2 堆
堆,几乎所有创建的Java对象实例,都是被直接分配到堆上的,堆被所有的线程所共享,在堆上区域,会被垃圾回收器做进一步划分,如新生代、老生代。
1.3 方法区
方法区与堆一样,也是所有的线程所共享,存储被虚拟机加载的元数据,包括类信息、常量、静态变量等。
方法区是一种Java虚拟机的规范,由于方法区存储的数据和堆中存储的数据一致,实际上也是堆。
1.4 运行时常量池
略
1.5 直接内存
略
2. 程序执行的内存分析过程
Java虚拟机的内存可以简单的分为三个区域:虚拟机栈stack,堆heap,方法区method area。
2.1 虚拟机栈的特点
-
栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧
-
JVM为每个线程创建一个栈,用于存放该线程执行方法的信息
-
栈属于线程私有,不能实现线程间的共享
-
栈的存储特性是“先进后出,后进先出”
-
栈是由系统自动分配,速度快,栈是一个连续的内存空间
2.2 堆的特点
-
堆用于存储创建好的对象和数组
-
JVM只有一个堆,被所有线程共享
-
堆是一个不连续的内存空间,分配灵活,速度慢
2.3 方法区(静态区)特点
-
方法区是Java虚拟机规范,可以有不同实现
-
JVM只有一个方法区,被所有线程共享
-
方法区实际也是堆,只是用于存储类、常量相关的信息
-
用来存放程序中永远是不变或唯一的内容
3. 垃圾回收机制与回收算法
3.1 基本概念
垃圾回收主要针对的是堆中的对象,包括对象空间的分配和释放。
-
对象空间的分配:利用new关键字创建即可
-
对象空间的释放:将对象赋值为null即可,垃圾回收器将负责回收所有“不可达”对象的内存空间
任何一种垃圾回收算法主要做两件事
-
发现无用对象
-
回收无用对象的内存空间
3.2 垃圾回收算法
-
引用计数法
堆中每个对象都对应一个引用计数器,当有引用指向这个对象时,引用计数器加1,而当指向该对象的引用失效时(引用变为null),引用计数器减1,最后如果该对象的引用计数器的值为0,则Java垃圾回收器认为该对象时无用对象并对其进行回收。
优点:算法简单
缺点:循环引用的无用对象无法识别
-
引用可达法(根搜索算法)
程序把所有的引用关系看作一张图
-
还有其他方法
4. 通用的分代垃圾回收机制
1.年轻代、年老代、永久代
Eden(年轻代)、Survivor(年轻代)、Tenured/Old(年老代)
所有新生成对象都是在Eden中,年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。当“年轻代”区域存满之后,放入到年老代区域。
年轻代中经历了N(默认15)次清理后仍存在的对象,放入年老代中。
永久代JDK8之后就取消了,用metaspace元数据空间和堆替代。
2.清理工具
Minor GG:清理年轻代区域
Major GC:清理年老代区域
Full GC:清理年轻代、年老代、成本较高,会对性能产生影响
5. 开发中容易造成内存泄漏的操作
-
创建大量无用对象
-
静态集合类的使用
-
各种连接对象(IO流对象,数据库连接对象,网络连接对象)未关闭
-
监听器的使用