Java虚拟机内存模型(Java运行在虚拟机之上,虚拟机帮Java屏蔽底层的指令集,让Java能够跨平台运行)
内存模型以及分区,需要详细到每个区放什么?
方法区(method area): 方法信息 本地方法栈(native method area): 本地方法 堆(heap): 堆在内存中并不是一块连续的区域,物理上是分散的,但逻辑上是连续的,遇到一条new的指令时,为新生对象分配内存空间,有两种方式,指针碰撞,空间列表
指针碰撞: 将内存逻辑上分为两边,一边是空闲的,一边是在用的,指针指向分界点,当需要分配内存的时候只要移动指针即可,只适用于内存规整的情况 空间列表: 虚拟机必须维护一个列表,用于记录哪些内存是可用的,在需要进行分配的时候,就从列表中找出一块足够大的空间进行分配并更新列表 栈(stack): 主要用来存放基本类型变量,局部变量以及对象的引用,方法的调用出入,栈的内存区域是连续的,有大小限制的,如果超出了就会抛出stackOverflowError异常,每个方法的调用都会对应着一个栈帧,有栈帧的入栈就有栈帧的出栈 堆是存放对象以及数组的区域,分为年轻代和年老代
年轻代又被分为一个Eden和两个Survivor区,即伊甸园和存活区 假设有10个方格,则其中8个是Eden区,两个是Survivor区 对象会在Eden区创建,当这两个区满了之后会将还存活的对象复制到另一个空白区Minor GC. 年轻代的对象有98%都是朝生夕死的 如果年轻代不够放了,就放在年老代 还有一种情况,对象在年轻代中存活的太久了 每当进行一次复制回收的时候,还在年轻代中存活的对象就会加1岁,默认15岁就到年老代 标记--清除--整理(标记好了就清除掉,最后整理成逻辑连续的区域) 年老代存活的一般是大对象或很难死去的对象 堆的设置
-Xms 10 m 堆的最小内存 10M -Xmx 10 m 堆的最大内存 10M -Xmn 10 m 设置新生代的内存大小 Java中GC标记(Garbage Collection)
标记就是对一些已死的对象打上记号,有以下两种方法
引用计数: 实现起来比较简单,就是给对象添加一个引用计数器,每当有一个地方引用它时就加1,引用失效时就减1,当计数器为0时就标记可回收,但很多主流的虚拟机并没有采用这种方法,因为它很难解决几个对象之间循环引用的问题 可达性分析: 通过将一些称为“GC Roots”的对象作为起始点,从这些节点开始搜索和该节点发生直接或者间接引用关系的对象,将这些对象以链的形式组合起来,形成一张“关系网”,又叫做“引用链”,最后垃圾回收器就回收一些不在这张关系网上的对象
栈帧中的引用对象(栈中的) 静态属性引用的对象(方法区中的) 常量引用的对象(方法区中的) 本地方法栈中JNI引用的对象(本地方法栈中的) Java中鲜为人知的二次标记
所有的类都继承了Object类,因此,也默认实现了finalize方法。在该对象被回收之前,该对象的finalize方法会被调用。这里的被回收之前指的就是被标记之后,如果开发者重写了finalize方法,则该对象会被重新加入到引用链,即关系网中。面对同一个对象,他的finalize方法只会被调用一次 二次标记
第一次标记不在“关系网”中的对象 第二次的话,就要先判断该对象有没有重写finalize方法
如果没有,就直接回收 如果重写了,则先放到一个队列中,并由虚拟机建立一个低优先级的线程来执行它,随后进行第二次小规模标记 从GC日志分析堆内存
由于GC线程和程序线程是并发执行的,当GC线程标记好了一个对象,此时程序中的线程又将该对象重新加入到了引用链中,虚拟机的解决办法是在一些特定位置设置一些“安全点”,当程序运行到这些“安全点”的时候就会暂停所有当前运行的线程(Stop The Word, STW), 暂停后重新找“GC Roots"进行关系的重建 常见安全点的位置
循环的末尾 方法临返回前/调用方法的call指令后 可能抛出异常的位置 找到”GC Roots"也是花很长时间的,通过采用一个OopMap的数据结构来记录系统中存活的“GC Roots", 通过解释OopMap就可以找到堆中的对象,这种方式也叫准确式GC GC和full GC是针对整个堆以及永久代的,时间长,尽量减少full GC的次数 Java中年轻代收集器(采用复制的收集算法)
Serial收集器: 一个单线程收集器,在进行回收的时候,必须暂停其它所有的工作进程,直到收集结束,用户体验不佳 ParNew收集器: 这个是Serial收集器的多线程版本,适用于多核CPU的设备 Parallel Scavenge收集器,默认的年轻代收集器,关注的是一个可控的吞吐量,吞吐量=运行代码的时间/(运行代码的时间+GC的时间),开启自适应调节策略 Java中年老代收集器,一般是大对象以及生命很顽强的对象(标记--清除--整理)
Serial Old收集器: 是Serial收集器的老年代版本,同样是单线程 Paraller Old收集器: 关注系统的吞吐量 CMS(Concurrent Mark Sweep)收集器: 是一种以最短停顿时间为目标的收集器 标记
初始标记----需要STW,直接关联 并发标记----不需要STW,间接关联 重新标记----需要STW,修改在上一步标记中有了变动的对象 并发清除
转载于:https://www.cnblogs.com/wjf0/p/8596180.html