JVM基础概念整理

本文详细介绍了JVM的内存区域,包括线程私有和共享区域,如程序计数器、虚拟机栈、本地方法栈、Java堆和方法区。探讨了Java堆和方法区的内存溢出异常,以及如何判断对象死亡的引用计数法和可达性分析算法。深入讲解了垃圾回收器的工作原理,包括不同垃圾回收算法如标记-清除、复制、标记-整理和分代收集。此外,还涉及到了JVM的内存分配策略,如对象在Eden区的分配、大对象直接进入老年代等。最后,提到了一些JVM性能检测和故障处理的工具,如jps、jstat、jmap等。
摘要由CSDN通过智能技术生成

JVM

JVM简介

虚拟机:通过软件模拟的具有完整硬件功能的、运行在一个完全隔离环境中的完整的计算机系统。

JVM:通过软件模拟Java字节码的指令集,JVM中只保留了PC寄存器

内存区域与内存溢出异常

1.运行时数据区域

在这里插入图片描述

线程私有区域

程序计数器、Java虚拟机栈、本地方法栈

线程私有:生命周期与具体线程相同,随着线程的创建而创建,随着线程销毁,对应空间回收

线程共享区域

java堆、方法区、运行时常量池

1.1程序计数器

记录程序当前执行地址

如果当前线程执行一个java方法,程序计数器记录正在执行的虚拟机字节码指令的地址;

如果当前线程执行一个native方法,计数器值为空;

1.2Java虚拟机栈

java方法执行的内存模型,例如:方法执行->入栈(局部变量表相当于虚拟机栈的一部分)

每一个方法执行时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用到执行完成的过程中,对应一个栈帧在虚拟机栈中出栈入栈的过程;

局部变量表:8大基本数据类型、对象引用;局部变量表所需的内存在编译期间完成

产生两大异常:

(1)线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),抛出StackOverFlowError异常

(2)虚拟机在动态扩展时无法申请到足够的内存,抛出OutOfMemoryError(OOM)异常

1.3本地方法栈

为虚拟机使用的native方法服务

在HotSpot虚拟机中,本地方法栈和虚拟机栈是同一块内存区域

1.4Java堆

存放内容:对象实例

所有对象的实例以及数组都要在堆上分配

Java堆是垃圾回收器管理的主要区域,也可称“GC”堆;

Java堆可以处于物理上不连续的内存空间中;

Java堆在主流的虚拟机上是可扩展的(-Xmx设置最大值,-Xms设置最小值)

产生异常:

如果在堆中没有足够的内存完成实例分配并且堆也无法再拓展时,抛出OOM异常

1.5方法区

存储内容:已被虚拟机加载的类信息、常量、静态变量、即时编译器编译的代码等数据

产生异常:

方法区无法满足内存分配需求时,抛出OOM异常

1.6运行时常量池

方法区的一部分

存储内容:字面量、符号引用

字面量:字符串(JDK1.7后移动至堆中)、final常量、基本数据类型的值

符号引用:类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符

2.Java堆溢出

2.1产生异常

即内存溢出异常(OOM),三个条件全部满足,产生该异常

(1)不断创建对象(2)保证GC Roots到对象之间有可达路径(3)对象数量达到最大堆容量

2.2异常处理分析

(1)java堆内存溢出,异常信息提示(Java heap space)

(2)判断是内存泄漏还是内存溢出

内存泄漏:泄露对象无法被GC

内存溢出:内存对象确实还应该活着

1.调大内存;2.检查对象的生命周期是否过长

3.虚拟机栈和本地方法栈溢出

虚拟机栈的两大异常

(1)线程请求的栈深度大于虚拟机所允许的深度(-Xss设置栈容量),抛出StackOverFlowError异常

(2)虚拟机在动态扩展时无法申请到足够的内存,抛出OutOfMemoryError(OOM)异常

如果因为多线程导致内存溢出问题,在不减少线程数的情况下,只能减少最大堆和减少栈容量的方法来换取更多线程

垃圾回收器与内存分配策略

1.判断对象已"死"

Java堆中的所有对象实例,垃圾回收器对堆进行垃圾回收之前。首先会判断对象是否存活

1.1引用计数法

使用分析:给对象加一个引用计数器,引用一次,计数器+1,当引用失效时,计数器-1;任何时刻计数器为0的对象已"死"

不足:在主流的JVM中没有选用引用计数器法来管理内存,最主要的原因是引用计数器法无法解决对象的循环引用问题

循环引用栗子:

public class Main{
    public Object instance = null;
    
    public static void testGC(){
        Main testA = new Main();
        Main testB = new Main();
        //两个对象互相引用
        testA.instance = testB;
        testB.instance = testA;
        testA = null;
        testB = null;
        System.gc();
    }
    
    public static void main(String[] args) {
        testGC();
    } 
}
1.2可达性分析算法

核心思想:以"GC Roots"对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为"引用链",当一个对象到GC Roots没有任何的引用链相连(从GC Roots到这个对象不可达)时,证明此对象是不可达的;

在这里插入图片描述

GC Roots对象包含:
(1)虚拟机栈(栈帧中的本地变量表)中引用的对象;
(2)方法区中类静态属性引用的对象;
(3)方法区中常量引用的对象;
(4)本地方法栈中(Native方法)引用的对象;

引用的扩充:

(1)强引用:new出来的,只要JVM中存在任何一个强引用,即便内存不够用,也无法回收此对象

ÿ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值