java通关整理-JVM内存管理

java通关整理汇总-Java基础、计算机网络、数据库、设计模式、框架、算法模板、笔试


网上收集整理,仅供笔记参考学习

1.JVM内存管理

在这里插入图片描述
JVM体系结构:

  • 类装载器ClassLoader:用来装载.class文件
  • 执行引擎:执行字节码,或者执行本地方法
  • 运行时数据区:方法区、堆、Java栈、程序计数器、本地方法栈

各个部分存储的内容:
在这里插入图片描述

0.1 Java类加载机制

java编译器将 .java 文件编译成扩展名为 .class 文件。.class 文件中保存着java转换后,虚拟机将要执行的指令。
当需要某个类的时候,java虚拟机会加载 .class 文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程被称为类的加载。
在这里插入图片描述
加载
类加载过程的一个阶段,ClassLoader通过一个类的完全限定名查找此类字节码文件,并利用字节码文件创建一个class对象。

验证
目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身的安全,主要包括四种验证:文件格式的验证,元数据的验证,字节码验证,符号引用验证。

准备
为类变量(static修饰的字段变量)分配内存并且设置该类变量的初始值,(如static int i = 5 这里只是将 i 赋值为0,在初始化的阶段再把 i 赋值为5),这里不包含final修饰的static ,因为final在编译的时候就已经分配了。这里不会为实例变量分配初始化,类变量会分配在方法区中,实例变量会随着对象分配到Java堆中。

解析
这里主要的任务是把常量池中的符号引用替换成直接引用

初始化
这里是类记载的最后阶段,如果该类具有父类就进行对父类进行初始化,执行其静态初始化器(静态代码块)和静态初始化成员变量。(前面已经对static 初始化了默认值,这里我们对它进行赋值,成员变量也将被初始化)

类加载器的任务是根据类的全限定名来读取此类的二进制字节流到 JVM 中,然后转换成一个与目标类对象的java.lang.Class 对象的实例,在java 虚拟机提供三种类加载器,引导类加载器,扩展类加载器,系统类加载器。

1.1 (Java 虚拟机)栈

每个方法在执行时都会床创建一个栈帧,其中最中要的四部分是局部变量表、操作数栈、动态链接、方法出口
一个方法从调用到执行结束,就对应一个栈帧中入栈出栈的过程。
局部变量表:存放变量的值
操作数栈:执行数据计算操作
动态链表:每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接。
方法出口:方法执行完毕

1.1.1 栈内部结构

一个方法对应一个栈帧
一个线程/一个主函数中有多个方法
程序计数器:记录程序运行到哪一行代码
栈:
本地方法栈:本地的方法。如:线程启动的start()方法。
在这里插入图片描述

1.2 本地方法栈

Java 虚拟机栈:Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,
本地方法栈:登记本地Native 方法,在execution engine执行的时候加载本地方法库。

1.3 堆

堆是用来存储对象实例以及数组
在开发过程使用的new对象,只要通过new创建的对象的内存的对象都在堆分配
堆是Java垃圾收集器管理的主要区域,Java的垃圾回收机制会自动进行处理。

1.3.1 堆内部结构:年轻代和老年代

堆空间分为老年代(2/3)和年轻代(1/3)
老年代内存:年轻代内存 2:1
年轻代:8:1:1

在这里插入图片描述

1.3.2 垃圾回收机制(GC)

Minor GC:如果 Eden 空间占满了, 会触发 minorGC。 MinorGC 后仍然存活的对 象会被复制到 S0 中去。这样 Eden 就被清空可以分配给新的对象。 又触发了一次 MinorGC , S0 和 Eden 中存活的对象被复制到 S1 中, 并且 S0 和 Eden 被清空。(复制算法

当每次对象从Eden复制到SurvivorSpace或者从SurvivorSpace中的一个复制 到另外一个,有一个计数器会自动增加值。 默认计数达到15时,就会把对象转移到老年代中去。

Full GC:老年代的空间被占满会触发老年代的 GC,也被称为 FullGC。FullGC 是一个 压缩处理过程,所以它比 MinorGC 要慢很多。“标记-清除(Mark-Sweep)”的算法。

一次Full GC就需要把进程停掉,STW(stop the world),这个时间时非常久的,所以要尽量避免Full GC

1.4 方法区

属于共享内存区域
存储常量、静态变量、类元信息

1.5 程序计数器

多线程是通过线程轮流切换来获得CPU执行时间的,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。

2.垃圾回收机制

2.1 判断是否为垃圾

2.1.1 引用计数法和可达性分析法

判断对象是否为垃圾
目前虚拟机基本上都用可达性分析法。
引用计数法:每个对象都有一个引用计数器,对象引用一次计数加1,引用失效一次计数减1,当GC时,计数器为0的对象就可以被回收。

可达性分析法:从GC ROOT起点出发,可以遍历到的节点对象标记,未标记/没有遍历到的对象就是可以被回收的对象。

有些对象的引用计数不为0,但是永远不会被访问了(类似在可达性分析法中,GC ROOT已经消除了,原来GC ROOT下面的节点就不会在被访问),这时用引用计数法就无法清除,可达性分析法可以。

2.2 垃圾收集的方法

2.2.1 复制算法

(在Minor GC中),它将可用内存按照容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,它将还存活着的对象复制到另一块上面,然后再把已经使用过的内存空间一次性清理掉。

2.2.2 标记-清除

(在Full GC中),没有与GC Roots相连接的引用链的对象就是未标记的对象,然后在将未标记的对象删除
缺点有两个:一个是效率问题,标记和清除这两个过程的效率都不高;另外一个是碎片问题,标记清除之后会产生大量不连续的内存碎片,可能会导致程序在以后的运行过程中需要分配较大对象时由于无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作

2.2.3 标记-整理

1.复制收集算法在对象存活率较高时就要执行较多的复制操作,效率将会变低
2.老年代都是不易被回收的对象,对象存活率高,因此一般不能直接选用复制算法
标记过程仍然与"标记-清除"算法一样,但后续整理过程不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

2.2.4 分代收集

不是新的方法,就是上面方法的组合,根据年轻代和老年代的特点采用最适当的收集算法
在新生代中,每次垃圾收集时都有大批对象死去,只有少量存活,那就选用复制算法。而老年代对象存活率高、没有额外空间对它进行分配担保,就必须使用"标记-清除"或"标记-整理"算法来进行回收。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值