jvm大致内容后续进行细致补充,有错欢迎指出

1.JVM:
  • jvm:jvm是java的运行环境(java二进制字节码的运行环境)

  • 好处:一次编写到处运行

    自动内存管理,垃圾回收机制

2.程序计数器:
  • 线程私有的,每个线程一份,内部保存的字节码的行号,用于记录正在执行的字节码文件指令的地址

3.堆:
  • 线程共享区域,主要保存对象实例,数组等,当堆内存中没有空间可分配给实例,也无王法在扩展时,就会抛出OutOfMemory Error异常

  • 堆中分为年轻代和老年代2个区域,年轻代被划分为3个区域,Eden区和2个大小严格相等的Survivor区,在每次垃圾回收时,Eden区中存活的对象会被移到其中一个Survivor区。Survivor区用于存放从Eden区复制过来的存活对象,根据JVM的策略,在经过几次垃圾回收集后,仍然存活于Survivor的对象将被移动到老年区间

    老年区主要保存生命周期长的对象,一般是一些老的对象

  • jdk1.7与jdk1.8的区别:在jdk1.8后,方法区(元空间,永久代)移出堆将数据存储在本地内存里面,因为随着动态类的加载,方法区内存会变得不可控,容易导致堆内存不足,方法区主要存在变量,静态变量,类信息,编译后的代码

4.虚拟机栈:
  • 每个线程运行的所需要的内存,称为虚拟机栈,每个栈有多个栈帧组成,每个栈帧对应相应着每次的方法调用时所占用的内存,

    每个线程只有一个活动栈帧,对应正在执行的那个方法

  • 垃圾回收主要指就是堆内存,当栈帧弹栈以后,内存就会释放

  • 栈内存分配空间不是越大越好,还要看具体业务实现,默认的栈内存通常为1024k,栈帧过大会导致线程数变少

  • 如果方法内局部变量没有逃离方法的作用范围,他是线程安全的,如果局部变量引用了对象,并且逃离的方法的作用范围,需要考虑线程安全

  • 栈帧过多导致内存溢出,典型问题1:递归,栈帧过大导致栈内存溢出

5.方法区:
  • 方法区是各个线程所共享的存储区域

  • 方法区存储类的信息,运行时常量池,存储在本地内存中

  • 在虚拟机启动时创建,关闭后销毁

6.运行时常量池:
  • 常量池可以看成一张表,虚拟机的运行指令根据这张表常量找到要执行的类名,方法名,参数类型,字面量

  • 当类被加载时,他的常量池信息就会被放到运行时的常量池,并把里面的符号引用改为真实引用

7.直接内存:
  • 直接内存并不属于JVM中的内存结构,不由JVM进行管理,是虚拟机的系统内存

  • 常见于NOI的操作,用于数据的缓存区域,分配的成本较高,但读写性能较高,不受JVM的内存管理

    类加载器:用于装载字节码文件(.class文件)

    运行时数据区:用于分配存储空间

    执行引擎:执行字节码文件或本地方法

    垃圾回收器:用于对JVM中的垃圾内容进行回收

8.类加载器:
  • jvm只会运行二进制文件,类加载器会将字节码文件加载到jvm中,从而使java程序能够运行起来

  • 类加载器根据各自加载范围的不同,划分为四种类加载器:

    启动类加载器(BootStrap ClassLoader)

    该类并不继承ClassLoader类,其是由C++编写实现。用于加载

    ** JAVA_HOME/jre/lib**目录下的类库。

    扩展类加载器(ExtClassLoader)

    该类是ClassLoader的子类,主要加载JAVA_HOME/jre/lib/ext目录中的类库。

    应用类加载器(AppClassLoader)

    该类是ClassLoader的子类,主要用于加载classPath下的类,也就是加载开发者自己编写的Java类。

    自定义类加载器:

    开发者自定义类继承ClassLoader,实现自定义类加载规则。

9.双亲委派模型:
  • 加载一个类先委托上一级加载器进行加载,如果委托的也有上一级则继续委托,如果上级没有被加载出来,子加载器则尝试加

  • 通过双亲委派可以防止某一个类被重复加载,当父类加载后则无需继续加载,保证唯一性

  • 为了安全保证核心类库不能被篡改

10.类装载过程:
  • 加载:查找和导入字节码文件

  • 验证:确保class文件的准确性

  • 准备:为类变量分配空间,并赋予初始值

  • 解析:把类中的符号引用转化为直接验证

  • 初始化:对类的静态变量,静态代码块执行初始化操作

  • 使用:JVM开始从入口方法开始执行用户的程序代码

  • 卸载:当用户程序代码被执行完毕后,JVM边开始销毁创建的对象

11.对象什么时候可以被回收:
  • 如果一个对象或者多个对象没有任何的引用执向他,那么这个对象就行垃圾,如果定位了垃圾,就可能被垃圾回收机制回收

    定位垃圾的方法有两种:可达性分析,引用计数器

  • 引用计数器:一个对象被引用了一次,在当前的对象头上递增一次引用次数,如果这个对象的

    引用次数为0,代表这个对象可回收,当对象间出现了循环引用的话,则引用计数法就会失效

  • 可达性分析算法:会存在一个根节点【GC Roots】,引出它下面指向的下一个节点,再以下一个

    节点节点开始找出它下面的节点,依次往下类推。直到所有的节点全部遍历完毕。

    根对象是那些肯定不能当做垃圾回收的对象,就可以当做根对象

12..jvm的垃圾回收算法:
  • 标记清除算法:步骤分为两步:标记和清除,首先使用可达分析算法得出的垃圾进行标记,然后对这些标记为可回收的垃圾进行回收

    效率较低,标记和清除两个动作都需要遍历所有的对象,并且在GC时,需要

    停止应用程序,对于交互性要求比较高的应用而言这个体验是非常差的。

    (重要)通过标记清除算法清理出来的内存,碎片化较为严重,因为被回收

    的对象可能存在于内存的各个角落,所以清理出来的内存是不连贯的。

  • 标记整理算法:在标记时跟标记清楚算法差不多,但清除时会把所有存活的对象都移向一端,清除边界以外的对象,解决了碎片化问题,算法多了一步,对象移动内存位置的步骤,其效率也有有一定的影响。与复制算法对比:复制算法标记完就复制,但标记整理算法得等把所有存活对象都标记完毕,再进行整理

  • 复制算法:复制算法是把内存分为同等大小的两块空间,每次就使用其中的一块,在进行垃圾回收时,会把所有存活的对象,复制到另一块空间上面,然后将该空间进行清空,如果内存中的垃圾对象较多,需要复制的对象就较少,这种情况下适合使用该方式并且效率比较高,反之,则不适合

    在垃圾对象多的情况下,效率较高

    清理后,内存无碎片:

    分配的2块内存空间,在同一个时刻,只能使用一半,内存使用率较低

  • 分代回收算法:对堆内存进行年龄划分,对不同的区域使用合适的垃圾回收机制

13.,jvm的分代回收:
  • 在jdk1.8时,队3被分成2块空间,新生代和老年代(内存比为1:2),对于新生代,内部又被分为了三个区域。Eden区,from区,to区(8:1:1),

  • 回收策略:新创建的对象,都会先分配到eden区

    当伊甸园内存不足,标记伊甸园与 from(现阶段没有)的存活对象

将存活对象采用复制算法复制到 to 中,复制完毕后,伊甸园和 from 内存都得到释放

经过一段时间后伊甸园的内存又出现不足,标记eden区域to区存活的对象,将存活的对象复制到from区

当幸存区对象熬过几次回收(最多15次),晋升到老年代(幸存区内存不足或大对象会导致提前晋升)

  • MinorGC【young GC】发生在新生代的垃圾回收,暂停时间短(STW)

    Mixed GC 新生代 + 老年代部分区域的垃圾回收,G1 收集器特有

    FullGC: 新生代 + 老年代完整垃圾回收,暂停时间长(STW),应尽力避免

14.jvm有哪些垃圾回收器:
  • 串行垃圾收集器:垃圾回收时,只有一个线程在工作,并且java应用中的所有线程都要暂停(STW),等待垃圾回收的完成

  • 并行垃圾收集器 :垃圾回收时,多个线程在工作,并且java应用中的所有线程都要暂停(STW),等待垃圾回收的完成

  • CMS(并发)垃圾收集器:相对较旧的并发垃圾收集器,适用于需要减少停顿时间的应用。分为初始标记、并发标记、重新标记和并发清理四个阶段。

15.G1垃圾回收器:
  • 应用于新生代和老年代,在**JDK9之后默认使用G1**

  • 划分成多个区域,每个区域都可以充当 eden,survivor,old, humongous,

  • 其中 humongous 专为大对象准备

  • 采用复制算法

  • 响应时间与吞吐量兼顾

  • 分成三个阶段:新生代回收、并发标记、混合收集

  • 如果并发失败(即回收速度赶不上创建新对象速度),会触发 Full GC

16.java的内存泄露排查顺序:
  • 通过jmap指定打印他的内存快照 dump

  • 通过工具, VisualVM(Ecplise MAT)去分析 dump文件

    VisualVM可以加载离线的dump文件

  • 通过查看堆信息的情况,可以大概定位内存溢出是哪行代码出了问题

17.cpu飙高和排查

  • 使用top命令查看占用cpu的情况

  • 通过top命令查看后,可以查看是哪一个进程占用cpu较高,上图所示的进程

    为:30978

  • 查看当前线程中的进程信息

  • 可以根据线程 id 找到有问题的线程,进一步定位到问题代码的源码行号

    执行命令

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值