第三天虚拟机篇

一、JVM内存结构
1.方法区:存储编译后的类、常量等
2.堆内存:存储对象
3.程序计数器:存储当前执行的指令地址
4.虚拟机栈:java栈,存储局部变量、方法参数、返回值以及异常处理信息
5.本地方法栈:存储本地方法的执行状态信息
以上是JVM内存结构的主要部分,其中除了方法区外其他部分都是java程序员直接操作和调优的重要部分
执行引擎:
解释器:先要到方法区获得到该方法的字节码指令,然后将字节码指令解释为机器码执行
即时编译器:对热点数据代码编译成机器码缓存,提高执行性能和效率
垃圾回收:这个类加载器对象加载的所有类对象,这些类对象对应的所有实例对象都没人引用时,GC 时就会对它们占用的对内存进行释放
永久代:是 Hotspot 虚拟机对 JVM 规范的实现(1.8 之前)
元空间:是 Hotspot 虚拟机对 JVM 规范的另一种实现(1.8 以后),使用本地内存作为这些信息的存储空间

二、JVM内存参数
1.Xms 最小堆内存(包括新生代和老年代)
2.Xmx 最大对内存(包括新生代和老年代)
3.通常建议将-Xms与-Xmx设置为大小相等,即不需要保留内存,不需要从小到大增长,这样性能较好。
4.-XX:NewSize 与 -XX:MaxNewSize 设置新生代的最小与最大值,但一般不建议设置,
由 JVM 自己控制
- -Xmn 设置新生代大小,相当于同时设置了 -XX:NewSize 与 -XX:MaxNewSize 并且取值相等
三、JVM垃圾回收
1.标记清除法:先找到一定不会回收的对象,然后找到被引用的对象做出标记,最后释放未加标记的对象占用的内存
2.标记整理法:比标记清除法多了一步整理的动作,将存活对象向一端移动,可以避免内存碎片产生
3.标记复制法

四、内存溢出
1.误用线程池导致的内存溢出示例
2.查询数据量太大导致的内存溢出示例
3.动态生成类导致的内存溢出示例
出现内存溢出的四种场景
1.堆内存耗尽->对象越来越多,又一直在使用,不能被垃圾回收
2.方法区内存耗尽->加载的类越来越多,很多框架都会在运行期间动态产生新的类
3.虚拟机栈累积->每个线程最多会占用 1 M 内存,线程个数越来越多,而又长时间运行不销毁时 出现 StackOverflowError 的区域
4.虚拟机栈内部->方法调用次数过多

五、类加载

1.类加载阶段:
1.1:加载:将类的字节码载入方法区,并创建类.class 对象如果此类的父类没有加载,先加载父类,加载是懒惰执行
1.2:链接:验证、准备、解析

1.3:初始化:
1.3.1 静态代码块、static 修饰的变量赋值、static final 修饰的引用类型变量赋值,会被合并成一个 <cinit> 方法,在初始化时被调用

1.3.2 static final 修饰的基本类型变量赋值,在链接阶段就已完成
1.3.3 初始化是懒惰执行

2.双亲委派机制
        2.1双亲委派机制就是优先委派上级类加载器进行加载
如果能找到这个类,由上级加载,加载后该类也对下级加载器可见,如果找不到这个类,则下级类加载器才有资格执行加载。
 系统类加载器-->平台类加载器-->启动类加载器
2.2双亲委派目的:
        2.21让上级类加载器中的类对下级共享(反之不行)即能让你的类能依赖到 jdk 提供的核心类
        2.22让类的加载有优先次序,保证核心类优先加载

六、四种引用
1.强引用:普通变量赋值即为强引用,如 A a = new A();通过 GC Root 的引用链,如果强引用不到该对象,该对象才能被回收
2.软引用:例如:SoftReference a = new SoftReference(new A())-->反射
3.弱引用:如果仅有弱引用引用该对象时,只要发生垃圾回收,就会释放该对象-->ThreadLocalMap 中的 Entry 对象
4.虚引用 PhantomReference a = new PhantomReference(new A(), referenceQueue);

猜你喜欢

转载自blog.csdn.net/weixin_71921932/article/details/129907764