虚拟机
2019-06-20 17:37:32 0 举报
AI智能生成
虚拟机
作者其他创作
大纲/内容
虚拟机
垃圾回收
概念
JVM来说,垃圾指的是在堆中死亡的对象所占据的内存空间
怎么知道对象死没死
引用计数法
缺点
额外的空间来存储计数器,以及繁琐的更新计数器以外;引用计数法还有一个重大的漏洞:无法处理循环引用
可达性分析
将一系列被称为GC Roots的变量作为初始的存活对象合集,然后从该合集出发,所有能够被该集合引用到的对象,并将其加入到该集合中,而不能被该合集所引用到的对象,并可对其宣告死亡。
在多线程环境下,其他线程可能会更新已经访问过的对象中的引用,而我们的可达性分析线程却没有同步到最新的内容。那么就会造成误报或者漏报。对于JVM来说误报顶多损失了部分垃圾回收的机会。漏报则比较麻烦,因为垃圾回收器可能回收了仍被引用的对象…
解决方案
Stop-the-world以及安全点
垃圾回收的三种方式
清除(sweep)
把死亡对象所占据的内存标记为空闲内存,并记录在一个空闲列表(free list)之中。当需要新建对象时,内存管理模块便会从该空闲列表中寻找空闲内存,并划分给新建的对象。
1、造成内存碎片。由于 Java 虚拟机的堆中对象必须是连续分布的,因此可能出现总空闲内存足够,但是无法分配的极端情况。比如:总空间100M,此时我们需要申请100M的数组。但是由于内存不连续,因此我们就会申请失败。2、分配效率较低。如果是一块连续的内存空间,那么我们可以通过指针加法(pointer bumping)来做分配。而对于空闲列表,Java 虚拟机则需要逐个访问列表中的项,来查找能够放入新建对象的空闲内存。
压缩(compact)
把存活的对象聚集到内存区域的起始位置,从而留下一段连续的内存空间。
压缩算法的性能开销
优点
能够解决内存碎片化的问题
复制(copy)
把内存区域分为两等分,分别用两个指针 from 和 to 来维护,并且只是用 from 指针指向的内存区域来分配内存。当发生垃圾回收时,便把存活的对象复制到 to 指针指向的内存区域中,并且交换 from 指针和 to 指针的内容。
现代设计方案
一般是把Java堆分作新生代和老年代,根据各个年代的特点采用最适当的收集算法
运行流程(概要)
类加载过程
1.加载
类加载器classLoader加载把java字节码加载到内存
2.连接
2.1验证
确保类加载的正确性。一般情况由javac编译的class文件是不会有问题的,但是可能有人的class文件是自己通过其他方式编译出来的,这就很有可能不符合jvm的编 译规则,这一步就是要过滤掉这部分不合法文件
2.2准备
为类的静态变量(static修饰的成员变量)分配内存,将其初始化为默认值 。我们都知道静态变量是可以不用我们手动赋值的,它自然会有一个初始值 比如int 类型的初始值就是0 ;boolean类型初始值为false,引用类型的初始值为null 。 这里注意,只是为静态变量分配内存,此时是没有对象实例的
2.3解析
把类中的符号引用转化为直接引用。解释一下符号引用和直接引用。比如在方法A中使用方法B,A(){B();},这里的B()就是符号引用,初学java时我们都是知道这是java的引用,以为B指向B方法的内存地址,但是这是不完整的,这里的B只是一个符号引用,它对于方法的调用没有太多的实际意义,可以这么认为,他就是给程序员看的一个标志,让程序员知道,这个方法可以这么调用,但是B方法实际调用时是通过一个指针指向B方法的内存地址,这个指针才是真正负责方法调用,他就是直接引用。
3.初始化
为类的静态变量赋予正确的初始值,上述的准备阶段为静态变量赋予的是虚拟机默认的初始值,此处赋予的才是程序编写者为变量分配的真正的初始值
运行时数据区
方法区
堆区
虚拟机栈
本地方法栈
程序计数器
堆内存溢出
栈内存溢出
方法区溢出
0 条评论
回复 删除
下一页