文章目录
内存分析
虚拟机内存模型 (了解)
- 程序计数器:在JVM规范中每个线程都有自己的程序计数器,存储当前线程正在执行的java方法的JVM地址, 即字段的行号。执行Native方法时,计数器为空。
- Java虚拟机栈:每个线程创建时会创建一个虚拟机栈,生命周期与线程一致, 线程退出时,线程的虚拟机也会回收。虚拟机内部保持一个个的栈帧,每次调用方法都会进行压栈, JVM对栈帧的操作只有出栈和压栈两种,方法结束会进行出栈操作。
- 堆:几乎所有创建的java对象实例,都是直接分配到堆上的。会分为新生代,老年代划分,Java虚拟机在启动时,可以使用Xmx之类的参数指定堆区域的大小。
- 方法区:方法区与堆一样,也是所有的线程所共享,存储被虚拟机加载的元(Meta)数据,包括类信息、常量、静态变量、即时编译器编译后的代码等数据。
程序执行过程内存分析 (重点)
-
Java 虚拟机的内存可以简单的分为三个区域:虚拟机栈 stack、堆 heap、
方法区 method area -
虚拟机栈
- 每个方法被调用会创建一个栈帧
- JVM为每个线程创建一个栈
- 栈属于线程私有
- “先进后出,后进先出”
- 由系统自动分配,速度快,连续空间
-
堆
- 存储创建好的对象和数组
- JVM只有一个堆,被所有线程共享
- 不是连续内存空间,分配灵活,速度慢
-
方法区(静态区)
- 只有一个方法区,被所有线程共享
- 也是堆,用于存储类和常量相关的信息(不变的内容)
- 用来存储程序中永远不变或唯一不变的内容
-
程序运行内存过程
public class Person {
String name;
int age;
public void show(){
System.out.println("姓名:"+name+",年龄:"+age);
}
}
public class TestPerson {
public static void main(String[ ] args) {
// 创建p1对象
Person p1 = new Person();
p1.age = 24;
p1.name = "张三";
p1.show();
// 创建p2对象
Person p2 = new Person();
p2.age = 35;
p2.name = "李四";
p2.show();
}
}
参数传值机制
垃圾回收(了解)
内存管理
- Java 的内存管理很大程度指的就是:堆中对象的管理,其中包括对象空间的分配和释放。
- 对象空间的分配:使用 new 关键字创建对象即可
- 对象空间的释放:将对象赋值 null 即可。垃圾回收器将负责回收所有”不可达”对象的内存空间。
垃圾回收过程
任何一种垃圾回收算法一般要做两件基本事情:
- 发现无用的对象
- 回收无用对象占用的内存空间。
垃圾回收机制保证可以将“无用的对象”进行回收。无用的对象指的就是没有任何变量引用该对象。Java 的垃圾回收器通过相关算法发现无用对象,并进行清除和整理。
垃圾回收算法
引用计数法
一个店里面有四张桌子,每个桌子有一个计数员,当计数员看到桌子上没人的时候就可以回收桌子了。
循环引用
引用可达法
- 程序把所有的引用关系看作一张图,从一个节点 GC ROOT 开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点
通用的分代垃圾回收机制
- 分代垃圾回收机制,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。我们将对象分为三种状态:年轻代、年老代、持久代。同时,将处于不同状态的对象放到堆中不同的区域。 JVM将堆内存划分为 Eden、Survivor 和 Tenured/Old 空间。
年轻代
- Eden区:所有新生成的对象首先放在Eden区,有个Minor GC会在Eden区满了之后立马启动清理内存
- S1区:Minor GC清理后继续使用的对象会留在Sl区,其他不使用的就被清理了,在S1区满了之后Minor GC会统一清理S1区。
- S2区:Minor GC清理S1区之后还在使用的对象留在S2区,其他没用的被清走,满了之后会放在年老代
年老代
- 当年老代和年轻代都满了之后,Major GC和Full GC(全量回收),拉一次大扫除,全面清理年老代和年轻代。
永久代
- 用于存放静态文件,如 Java 类、方法等。持久代对垃圾回收没有显著影响。
JVM调优和Full GC
在对JVM调优的过程中,很大一部分工作就是对Full GC的调节,有如下原因:
- 年老代被写满
- 永久代被写满
- System.gc()被显示调用
- 上一次GC之后help的各域分别配策略动态变化
开发中容易造成内存泄露的操作
- 创建大量无用对象
- 静态集合类的使用
- 各种连接对象(IO 流对象、数据库连接对象、网络连接对象)未关闭
- 监听器的使用不当
其他要点
- 程序员无权调用垃圾回收器
- 程序员可以调用 System.gc(),该方法只是通知 JVM,并不是运行垃圾回收器。尽量少用,会申请启动 Full GC,成本高,影响系统性能
- finalize 方法,是 Java 提供给程序员用来释放对象或资源的方法,但是尽量少用